Hemal Hemal - 1 month ago 76
React JSX Question

How to set component state based on Material UI selected table rows

Any pointers to help a learner out appreciated.

What I'm trying to build



A form with 2 inputs:


  • A text field (patient email)

  • An array (created by compiling a selection of table rows)



I am trying to set the component state to store the values of the text field and the array of selected table rows, so that the state can be passed on to the server onSubmit.

Code (table rows populate by placeholder data)



import React, { Component } from 'react';
import TextField from 'material-ui/TextField';
import RaisedButton from 'material-ui/RaisedButton';
import {Table, TableBody, TableFooter, TableHeader, TableHeaderColumn, TableRow, TableRowColumn} from 'material-ui/Table';

const tableData = [{
feedName: 'Flossing habit',
messageCount: '12 messages'
}, {
feedName: 'Post exo instructions',
messageCount: '5 messages'
}, {
feedName: 'Appointment feedback',
messageCount: '1 message'
}];

class NewPatient extends Component {
constructor (){
super();
this.state = ({
email: "",
feeds: []
});
this.setEmail = this.setEmail.bind(this);
this.handleSubmit = this.handleSubmit.bind(this);
this.onRowSelection = this.onRowSelection.bind(this);
}
setEmail(event) {
console.log(event.target.value);
this.setState({email: event.target.value})
}
handleSubmit(event){
event.preventDefault();
console.log(this.state);
//Meteor.call('console', this.state);
this.setState({email: ''});
}
onRowSelection(rows){
console.log(rows);
this.setState({feeds: rows})
}
render() {
let availableFeeds = tableData.map(feed=> {
return (
<TableRow key={feed.feedName}>
<TableRowColumn>{feed.feedName}</TableRowColumn>
<TableRowColumn>{feed.messageCount}</TableRowColumn>
</TableRow>
)});
return (
<form onSubmit={this.handleSubmit}>
<TextField
name='email'
value={this.state.email}
onChange={this.setEmail}
hintText='Patient email address'
/>
<Table multiSelectable={true} onRowSelection={this.onRowSelection}>
<TableHeader displaySelectAll={false}>
<TableRow>
<TableHeaderColumn>Feed Name</TableHeaderColumn>
<TableHeaderColumn>Number of messages</TableHeaderColumn>
</TableRow>
</TableHeader>
<TableBody>
{availableFeeds}
</TableBody>
</Table>
<RaisedButton type="Submit" label="Send" primary={true} />
</form>
)
}
}
;

export default NewPatient;


Problems I am facing



Setting the component state for the selected rows array. When I use:

onRowSelection(rows){
console.log(rows);
this.setState({feeds: rows})
}



  • The selected rows don't stay 'selected' and neither does the state reflect the selected rows.

  • If I remove the setState function from here, then selecting rows is suddenly possible - the console.log(rows) shows an updated array of the selected rows whenever the selection changes BUT, the table resets if you focus away from it (e.g. If you select a row and then move to the text field).






I suspect, but am not sure (and no idea how to use it if this is the issue, can't find anything in the documentation at http://www.material-ui.com/#/components/table ), that I need to add a function within 'onRowSelection' that manipulates the 'selected' boolean value within each row..?

Has anyone had any experience with this or sees something obvious that I am missing?

Thanks in advance to anybody who has gotten this far to reading this! Any advice/pointers to relevant links/documents much appreciated.

Answer

Answer after finding the solution with the help of Ryan at themeteorchef.com :

Main things of note: 1. Material-UI tables have a deselectOnClickaway property - make sure that is set to false! 2. We needed to find a way to set the 'selected' state for each row every time any other row is selected/deselected or if another part of the form (similar to Shouvik Roy's answer)

import React, { Component } from 'react';
import TextField from 'material-ui/TextField';
import RaisedButton from 'material-ui/RaisedButton';
// import { _ } from 'meteor/underscore';
import {Table, TableBody, TableFooter, TableHeader, TableHeaderColumn, TableRow, TableRowColumn} from 'material-ui/Table';

const tableData = [{
    feedName: 'Flossing habit',
    messageCount: '12 messages',
    selected: false,
}, {
    feedName: 'Post exo instructions',
    messageCount: '5 messages',
    selected: false,
}, {
    feedName: 'Appointment feedback',
    messageCount: '1 message',
    selected: false,
}];

class NewPatient extends Component {
    constructor (){
        super();
        this.state = ({
            email: "",
            feeds: tableData
        });
        this.setEmail = this.setEmail.bind(this);
        this.handleSubmit = this.handleSubmit.bind(this);
        this.onRowSelection = this.onRowSelection.bind(this);
    }
    setEmail(event) {
        console.log(event.target.value);
        this.setState({email: event.target.value})
    }
    handleSubmit(event){
        event.preventDefault();
        console.log(this.state);
        Meteor.call('console', this.state.email);
        this.setState({email: ''});
    }
    onRowSelection(rows){
        const selectedFeeds = [];
        this.state.feeds.forEach((feed, i) => {
            feed.selected = rows.indexOf(i) > -1;
            selectedFeeds.push(feed);
        });
    //  console.log(selectedFeeds);
        this.setState({feeds: selectedFeeds}, () => {
            console.log(this.state.feeds);
        });
    }
    render() {
        let availableFeeds = this.state.feeds.map((feed, i)  => {
            return (
                <TableRow key={feed.feedName} selected={feed.selected}>
                    <TableRowColumn>{feed.feedName}</TableRowColumn>
                    <TableRowColumn>{feed.messageCount}</TableRowColumn>
                </TableRow>
            )});
        return (
            <form onSubmit={this.handleSubmit}>
                <TextField
                    name='email'
                    value={this.state.email}
                  onChange={this.setEmail}
                  hintText='Patient email address'
                />
                <Table multiSelectable={true} onRowSelection={this.onRowSelection}>
                    <TableHeader displaySelectAll={false}>
                        <TableRow>
                            <TableHeaderColumn>Feed Name</TableHeaderColumn>
                            <TableHeaderColumn>Number of messages</TableHeaderColumn>
                        </TableRow>
                    </TableHeader>
                    <TableBody deselectOnClickaway={false}>
                        {availableFeeds}
                    </TableBody>
                </Table>
                <RaisedButton type="Submit" label="Send" primary={true} />
            </form>
        )
    }
}
;

export default NewPatient;