how to attach key press event on table cell in react js - reactjs

i have a table i wanna attach arrow keys to each cell wanna implement something like https://jsfiddle.net/rh5aoxsL/ in react but then not able to do so as some where m going wrong can anyone lemme know what has to be done
import React, { Component } from 'react';
import './App.css';
class App extends Component {
constructor(props){
super(props);
this.escFunction = this.escFunction.bind(this);
}
escFunction(event){
if(event.keyCode === 37) {
console.log("----------37---------------");
}
if(event.keyCode === 38) {
console.log("----------38---------------");
}
if(event.keyCode === 39) {
console.log("----------39---------------");
}
if(event.keyCode === 40) {
console.log("----------40---------------");
}
}
componentDidMount(){
document.addEventListener("keydown", this.escFunction, false);
}
componentWillUnmount(){
document.removeEventListener("keydown", this.escFunction, false);
}
render() {
return (
<div className="App">
<table >
<tbody>
<tr>
<td id="start" onKeyDown={this.escFunction}>1</td>
<td onKeyDown={this.escFunction}>2</td>
</tr>
<tr>
<td onKeyDown={this.escFunction}>3</td>
<td onKeyDown={this.escFunction}>4</td>
</tr>
</tbody>
</table>
</div>
);
}
}
export default App;
any help is appreciated

This is my code, just getting siblings.
Constants:
const UP_ARROW = 38;
const DOWN_ARROW = 40;
const LEFT_ARROW = 37;
const RIGHT_ARROW=39;
const TOTAL_CELLS_BY_ROW = (your_number_of_cols);
I have tr -> td -> div -> input, my focus is in inputs. (this is why i have some parentElement and childNodes.
TOTAL_CELLS_BY_ROW is my col count...
onKeyDown = (e) => {
var idx = e.target.parentElement.parentElement.cellIndex;
if (e.keyCode === LEFT_ARROW) {
if (e.target.parentElement.parentElement.previousElementSibling) {
e.target.parentElement.parentElement.previousElementSibling.childNodes[0].childNodes[0].focus();
}
}
if (e.keyCode === RIGHT_ARROW) {
if (e.target.parentElement.parentElement.nextElementSibling) {
e.target.parentElement.parentElement.nextElementSibling.childNodes[0].childNodes[0].focus();
}
}
if (e.keyCode === DOWN_ARROW) {
const nextRow = e.target.parentElement.parentElement.parentElement.nextElementSibling
if (nextRow) {
nextRow.childNodes[idx%TOTAL_CELLS_BY_ROW].childNodes[0].childNodes[0].focus();
}
}
if (e.keyCode === UP_ARROW) {
const previousRow = e.target.parentElement.parentElement.parentElement.previousElementSibling
if (previousRow) {
previousRow.childNodes[idx%TOTAL_CELLS_BY_ROW].childNodes[0].childNodes[0].focus();
}
}
}
Of course onKeyDown={this.onKeyDown} in each input.

I don't know this code is enough for you but as #Pardeep Dhingra explained in the comments you need onKeyDown instead of onKeyPress in your situation. Also, you should change your callback function. I've used tabIndex to start the initial move.
class App extends React.Component {
escFunction = ( event ) => {
if ( event.keyCode === 37 ) {
console.log( "----------37---------------" );
}
if ( event.keyCode === 38 ) {
console.log( "----------38---------------" );
}
if ( event.keyCode === 39 ) {
console.log( "----------39---------------" );
}
if ( event.keyCode === 40 ) {
console.log( "----------40---------------" );
}
}
render() {
return (
<div className="App">
<table>
<tbody>
<tr>
<td id="start" tabIndex="0" onKeyDown={this.escFunction}>
1
</td>
<td onKeyDown={this.escFunction}>2</td>
</tr>
<tr>
<td onKeyDown={this.escFunction}>3</td>
<td onKeyDown={this.escFunction}>4</td>
</tr>
</tbody>
</table>
</div>
);
}
}
ReactDOM.render(
<App />,
document.getElementById("root")
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Related

Conditional statement within react render meth

I am new to react and I am trying to add a condition within the render method so that if the value framework1 is empty I need not add a text within the HTML.
Below is my code.
buildResults = () => {
const {
results
} = this.state;
return {
<div className={`${block}__results`}>
<table>
<thead></thead>
<tbody>
{ results.map(item => this.buildResult(item)) }
</tbody>
</table>
</div>
}
buildResult = (data) => {
const {
framework1,
framework2
} = data;
return (
<tr className={`${block}__row`}>
<td className={`${block}__cell ${block}__cell--ticker`}>
/* I need to display the text "view" only if framework1 is not empty */
View
</td>
</tr>
)
}
Use an if statement to check whether the there is data, in this case, I am checking whether the data in framework1 is a string.
buildResults = () => {
const {
results
} = this.state;
return {
<div className={`${block}__results`}>
<table>
<thead></thead>
<tbody>
{ results.map(item => this.buildResult(item)) }
</tbody>
</table>
</div>
}
buildResult = (data) => {
const {
framework1,
framework2
} = data;
return (
<tr className={`${block}__row`}>
<td className={`${block}__cell ${block}__cell--ticker`}>
if (framework1.indexOf("ST1") ){
// display something else
}
else {
View
}
</td>
</tr>
)
}

ReactJS. How to get states of elements inside react component

Help me please to get states of elements inside react component or other some custom features with information which I need. Every of td tags contains react component Block1.
Simplified code structure below
class Block2 extends React.Component {
render() {
return (
<table>
<tbody>
<tr>
<td>
<Block1 />
</td>
<td>
<Block1 />
</td>
</tr>
</tbody>
</table>
)}}
Block1 - react component which contain div elements.
Block2 is inside component Block3. How to get states of Block1 from Block3 by click on some button?
Now, I can get list of Block1 and may see props, but I can't see states. Or I can get DOM td elements and see children classNames (which I looking for in states) but I can't see props...
Unless you use libraries like Redux, you have to do the following to solve your problem:
Store the state inside Block3 and not Block1. Then pass any function that changes this state as props from Block3 to Block2 to Block1. When any change occurs in Block1, call this function. The pattern should be:
class Block3 {
changeState(value) {
this.setState({ stateValue: value });
}
render() {
return (
<Block2 changeState={this.changeState}/>
)
}
}
class Block2 extends React.Component {
render() {
return (
<table>
<tbody>
<tr>
<td>
<Block1 changeState={this.props.changeState} />
</td>
<td>
<Block1 changeState={this.props.changeState} />
</td>
</tr>
</tbody>
</table>
)}}
class Block1 {
changeHandler(ev) {
this.props.changeState(ev.target.value);
}
render() {
return (
<button onClick={this.changeHandler}/>
)
}
}
If you really want to access the child state inside a parent component, consider using refs:
class Block2 {
render() {
return <Block1 ref={ (childComponent) => { this.block1Child = childComponent; } } />;
// Now you may use this.block1Child to access child component's state eg: this.block1Child.setState({})
}
}
EDIT: My solution after seeing your code:
import React, { Component } from 'react';
import './Hall.css';
class HallCol extends Component {
constructor(props) {
super(props);
this.state = {
chair_cls:'chair-default'
};
this.handleClick = this.handleClick.bind(this);
}
handleClick(e) {
let chair_cls = null;
if(this.state.chair_cls==="chair-default") {
chair_cls = 'chair-sold';
this.props.updateCount(1, this.props.seat_number);
} else {
chair_cls = 'chair-default';
this.props.updateCount(-1, this.props.seat_number);
}
this.setState({
chair_cls: chair_cls
});
}
render(){
return(
<div className={this.state.chair_cls} onClick={this.handleClick}>
<div className="backrest">
<p>{this.props.seat_number}</p>
</div>
<div className="armrest-left">
</div>
<div className="armrest-right">
</div>
</div>
);
}
}
class Table extends React.Component {
constructor() {
super();
this.genRow = this.genRow.bind(this); // this is method binding
}
genRow() {
var rows = this.props.rows;
return rows.map(function(v, i) {
var tmp = v.map(function(v2, j) {
return (
<td key={'td' + i + '_' + j} className='chair-cell' >
{v2}
</td>
);
});
return (
<tr key={'tr' + i}>
{tmp}
</tr>
)
});
}
render() {
return (
<table className="hall-grid" >
<tbody>
{this.genRow()}
</tbody>
</table>
);
}
}
class Hall extends React.Component {
constructor(props) {
super(props);
var rows_num = this.props.rows;
var cols_num = this.props.cols;
this.AddRow = this.AddRow.bind(this);
this.updateSeats = this.updateSeats.bind(this);
var row = [];
for (var i = 0; i < rows_num; i++) {
var col = [];
for (var k = 0; k< cols_num; k++) {
col.push(<HallCol row = {i+1} seat_number = {k+1} updateCount={this.updateSeats} />); // bind the passed function to parent
}
row.push(col);
}
this.state = {
rows: row,
bookedSeats: [],
count: 0
};
}
AddRow() {
let newRows = this.state.rows;
newRows.push([0, 0]);
this.setState({rows: newRows});
}
updateSeats(val, seat_number) {
let bookedSeatsUpdated;
if( val === 1 ) {
bookedSeatsUpdated = this.state.bookedSeats.concat(seat_number);
} else {
bookedSeatsUpdated = this.state.bookedSeats;
let index = bookedSeatsUpdated.indexOf(seat_number);
bookedSeatsUpdated.splice(index,1);
}
this.setState({
bookedSeats: bookedSeatsUpdated,
count: this.state.count + val
});
}
render() {
return (
<div className="hall">
<Table rows={this.state.rows} />
<button className = "btn-default" onClick={() => {
alert(this.state.count + 'seats : ' + this.state.bookedSeats);
} }>
TOTAL SOLD
</button>
</div>
);
}
}
export default Hall;

Issue with leave animation using React-Flip-Move

I'm using this module for my twitch API app: https://github.com/joshwcomeau/react-flip-move/
and currently having an issue with the leave animation. The enter animation works perfectly, fine, but unforunately, when I click 'x' on one of the channels, the element (in my case a ) moves up and to the right. How do I make it fade out in its current position?
import React, { Component } from 'react';
import { connect } from 'react-redux';
import FlipMove from 'react-flip-move';
import { selectUser, fetchUser, removeUser } from '../actions/index';
class UsersList extends Component {
constructor(props) {
super(props);
this.state = {
show: 'all',
};
this.fetchInitialUsers(this.props.initialUsers);
}
fetchInitialUsers(users) {
users.map(this.props.fetchUser);
}
renderUser(user) {
const { channelData, streamData } = user;
return (
<tr
key={channelData.display_name}
onClick={() => this.props.selectUser(user)}
className='list-item'>
<td>
<img src={channelData.logo} className='user-logo' />
</td>
<td>
{channelData.display_name}
</td>
<td>
{streamData.stream ?
<span className='online'>Online</span> :
<span className='offline'>Offline</span>}
</td>
<span
className="glyphicon glyphicon-remove"
onClick={() => this.props.removeUser(user)}></span>
</tr>
)
}
showOnline() {
this.setState({
show: 'online'
});
}
showOffline() {
this.setState({
show: 'offline'
});
}
showAll() {
this.setState({
show: 'all'
});
}
render() {
return (
<div className='col-sm-4'>
<div className='text-center'>
<div className='btn-group btn-group-sm' role='group'>
<button
className='btn btn-default'
onClick={this.showAll.bind(this)}>
All
</button>
<button
className='btn btn-default'
onClick={this.showOnline.bind(this)}>
Online
</button>
<button
className='btn btn-default'
onClick={this.showOffline.bind(this)}>
Offline
</button>
</div>
</div>
<div className='container'>
<table className='table table-hover'>
<thead>
<tr>
<th>Logo</th>
<th>Channel</th>
<th>Status</th>
</tr>
</thead>
{/* <tbody> */}
<FlipMove
typeName='tbody' enterAnimation='fade'
leaveAnimation='fade'>
{this.props.users.filter(user => {
const { show } = this.state;
const { streamData } = user;
if (show == 'online') {
return streamData.stream;
}
else if (show == 'offline') {
return !streamData.stream;
}
else {
return user;
}
}).map(this.renderUser.bind(this))}
</FlipMove>
{/* </tbody> */}
</table>
</div>
</div>
)
}
}
function mapStateToProps({ users, initialUsers }) {
return { users, initialUsers };
}
export default connect(mapStateToProps, { selectUser, fetchUser, removeUser })(UsersList);
just add maintainContainerHeight="true" to the flipmove attributes

React JS assign separate onclick event to every row of table

I have a table which have a setting icon as the last column and whenever a user clicks on it, it should pop open a setting menu. To toggle between active class I used state and passed it to the array.map function, but what is happening is whenever a user clicks on one setting icon all the menus open simultaneously and the reason is they all have same click event and same state variable. How can I change it to where only the clicked setting icon should have its menu opened? My code is given below.
import React, { Component, PropTypes } from 'react';
import '../../../assets/custom_css/tables/unstackable_very_basic_striped_users_table.css';
import { v4 } from 'node-uuid';
import Language from '../../../assets/language';
class UnstackableVeryBasicStripedUsersTable extends Component {
static propTypes = {
rows: PropTypes.array.isRequired
};
constructor(props) {
super(props);
this.getTableRows = this.getTableRows.bind(this);
this.open_setting_menu = this.open_setting_menu.bind(this);
this.state = {
is_action_menu_active: false
};
}
getTableRows() {
const { rows } = this.props;
return rows.map(row => {
let drop_down_class = (this.state.is_action_menu_active) ? "active" : "";
let menu_class = (this.state.is_action_menu_active) ? "transition visible" : "";
return <tr key={v4()}>
{row.map(info => {
return <td key={v4()}>
{info}
</td>
})}
<td>
<div className={"ui right pointing dropdown icon " + drop_down_class} onClick={this.open_setting_menu}>
<i className="setting icon"/>
<div className={"menu " + menu_class}>
<div className="item">Edit</div>
<div className="item">Delete</div>
</div>
</div>
</td>
</tr>
});
}
open_setting_menu() {
this.setState({
is_action_menu_active: !this.state.is_action_menu_active
});
}
render() {
return <table className="ui unstackable celled very basic striped table unstackable_very_basic_striped_table">
<thead>
<tr>
<th>{Language.name}</th>
<th>{Language.role}</th>
<th>{Language.department}</th>
<th>{Language.action}</th>
</tr>
</thead>
<tbody>
{this.getTableRows()}
</tbody>
</table>
}
}
export default UnstackableVeryBasicStripedUsersTable;
If you want to use a single component, you can save the index of the selected row in the state:
import React, { Component, PropTypes } from 'react';
import '../../../assets/custom_css/tables/unstackable_very_basic_striped_users_table.css';
import { v4 } from 'node-uuid';
import Language from '../../../assets/language';
class UnstackableVeryBasicStripedUsersTable extends Component {
static propTypes = {
rows: PropTypes.array.isRequired
};
constructor(props) {
super(props);
this.getTableRows = this.getTableRows.bind(this);
this.open_setting_menu = this.open_setting_menu.bind(this);
this.state = {
selected_row_index: 0,
is_action_menu_active: false
};
}
getTableRows() {
const { rows } = this.props;
return rows.map((row, index) => {
let drop_down_class = (this.state.is_action_menu_active && this.state.selected_row_index === index) ? "active" : "";
let menu_class = (this.state.is_action_menu_active && this.state.selected_row_index === index) ? "transition visible" : "";
return <tr key={v4()}>
{row.map(info => {
return <td key={v4()}>
{info}
</td>
})}
<td>
<div className={"ui right pointing dropdown icon " + drop_down_class} onClick={() => this.open_setting_menu(index)}>
<i className="setting icon"/>
<div className={"menu " + menu_class}>
<div className="item">Edit</div>
<div className="item">Delete</div>
</div>
</div>
</td>
</tr>
});
}
open_setting_menu(index) {
this.setState({
is_action_menu_active: !this.state.is_action_menu_active,
selected_row_index: index
});
}
render() {
return <table className="ui unstackable celled very basic striped table unstackable_very_basic_striped_table">
<thead>
<tr>
<th>{Language.name}</th>
<th>{Language.role}</th>
<th>{Language.department}</th>
<th>{Language.action}</th>
</tr>
</thead>
<tbody>
{this.getTableRows()}
</tbody>
</table>
}
}
export default UnstackableVeryBasicStripedUsersTable;

React - why is this component not rendering anything?

I am trying to render some child components in a parent component but nothing is rendering. I'm not getting any console errors but there is no render. I can't figure out why this may be happening. The application I am working on is built with React, using a flux architecture.
Here is my code:
Parent Component:
import React from 'react';
import TableWithDataHeader from './TableWithDataHeader.jsx';
import TableWithDataBody from './TableWithDataBody.jsx';
import TableWithDataRowForm from './TableWithDataRowForm.jsx';
import AppStore from '../../stores/AppStore';
export default class TableWithData extends React.Component {
state = {rows: [], isEditing: false};
componentDidMount() {
let json = AppStore.getCells();
let rows = this.state.rows;
for (let key in json) {
{rows[key] = json[key]};
}
this.setState({rows});
console.log(rows);
}
handleEdit = (row) => {
this.setState({isEditing: true});
};
editStop = (formKey) => {
this.setState({isEditing: false});
};
handleSubmit = () => {
console.log('hello');
};
render() {
let {rows, isEditing} = this.state;
console.log(rows);
return (
<div>
<div className="row">
<table className="table table-striped">
<thead>
<TableWithDataHeader />
</thead>
<tbody>
{rows.map(row => this.state.isEditing ?
<TableWithDataRowForm formKey={row.id} key={row.id} editStop={this.editStop(formKey)} handleSubmit={this.handleSubmit} /> :
<TableWithDataBody key={row.id} value={row.historycells.contents} handleEdit={this.handleEdit(row)} />
)}
</tbody>
</table>
</div>
</div>
);
}
}
RowForm:
import React from 'react';
export default class TableWithDataRowForm extends React.Component {
editStop = () => {
this.props.editStop();
};
handleSubmit = (e) => {
e.preventDefault();
this.props.handleSubmit();
};
render() {
return (
<tr>
<td></td>
<td>
<button className=""><i className="btn btn-default" onClick={this.editStop}></i>Cancel</button>
<button className="btn btn-success"><i className="fa fa-cloud" onClick={this.handleSubmit}></i>Save</button>
</td>
</tr>
);
}
}
Table Head:
import React from 'react';
import AppStore from '../../stores/AppStore';
export default class TableWithDataHeader extends React.Component {
addHeaders() {
let headerArray = AppStore.getTable().columns;
let headerList = headerArray.map((element, index) => {
return (
<th key={index} id={element.id} className="text-center">{element.name}</th>
);
});
return headerList;
}
render() {
return (
<tr>
{this.addHeaders()}
<th></th>
</tr>
);
}
}
Table Body:
import React from 'react';
export default class TableWithDataBody extends React.Component {
handleEdit() {
this.props.handleEdit();
}
render() {
return (
<tr>
{this.props.histroycells.map(cell => {
return <Cell key={cell.id} value={cell.contents} />
})}
<td>
<button className="btn btn-primary" onClick={this.handleEdit}><i className="fa fa-pencil"></i>Edit</button>
</td>
</tr>
);
}
}
The table header renders fine but neither the body of the table or the edit form shows up at all!
Any help would be much appreciated, especially examples!
Thanks for you time!
Maybe this will help:
Inside your <TableWithDataBody>component, you try to access this.props.historycells, but this isn't passed as a prop.
You render your table rows with:
<TableWithDataBody
key={row.id}
value={row.historycells.contents}
handleEdit={this.handleEdit(row)} />
Maybe if you change render to:
<TableWithDataBody
key={row.id}
historycells={row.historycells} // changed this parameter
handleEdit={this.handleEdit(row)} />
UPDATE:
The line which loops over the props should still read:
{this.props.historycells.map(cell => {
PS: please also fix typo in histroycells.
You have a typo in your code. histroycells in TableWithDataBody should be historycells.

Resources