Bigboss
Bigboss

Reputation: 365

Change state of a parent from the child in ReactJs

Supposing I have this parent component.

Parent.jsx

render() {
    const headers = ["id","desc1", "desc2", "actions"];
    return(
        <div>
            <input type = "text" placeholder = "Product Brand" value={ this.state.desc }/>
            <input type = "text" placeholder = "Product Brand" value={ this.state.desc2 }/>
            <button type = "button" onClick = { this.handleSubmit.bind(this) }>Add</button>

            <CustomTable mystate = { this.state } header = { headers } data = { this.props.store.productbrandlist }/>
        </div>
    )
}

and this CustomTable.jsx

renderHeaders(){
    return(
        this.props.header.map(function(header, index){
            return <th key={index}>{header}</th>
        })
    )
}

renderRows(){
    // console.log("here1");
    // return(
    //  <ListItem datarows = { this.props.data }/>
    // )
    return this.props.data.map((list, id) => <ListItem mystate = {this.props.mystate} key_id={id} key={id} col = {list}/> )
}

render(){
    return(
        <table className="table">
            <thead>
                <tr>{ this.renderHeaders() }</tr>
            </thead>
            <tbody>
                { this.renderRows() }
            </tbody>
        </table>
    )
}

and this component which render the rows of the table

render(){

    return(
        <tr key = { this.props.key_id }>
            { this.renderColumns() }
            { this.renderActions() }
        </tr>
    )
}
renderColumns(){
    var columns = []
    for (var key in this.props.col)
    {
        if (this.state.isEditing){
            columns.push(<td key = {key.id}><input ref = "txt" type = "text" value = { this.state.itemValue } onChange = { this.onTextChange.bind(this) } /></td>)
        }
        else
        {
            columns.push(<td key = {key.id}>{ this.props.col[key] }</td>)
            // this.setState({
            //  itemValue: key,
            //  isEditing: false
            // })

        }

    }
    return columns
}

renderActions(){
    if (this.state.isEditing){
        return (
            <td>
                <button type="button" onClick = { this.handleSaveClick.bind(this) }>Save</button>
                <button type="button" onClick = { this.handlCancelClick.bind(this) }>Cancel</button>
            </td>
        )
    }

    return(
        <td>
            <button type="button" onClick = { this.handleEditClick.bind(this) }>Edit</button>
            <button type="button" onClick = { this.handleDeleteClick.bind(this) }>Delete</button>
        </td>
    )
}

My question is how do I configure it in such a way that when I click on the button edit which is created in the ListItem Component. The data will be displayed in the inputbox which is created in the parent.jsx

Upvotes: 0

Views: 79

Answers (1)

sisanared
sisanared

Reputation: 4287

Looking at your code, you just simply need to pass a reference to a parent method to the desired child, through props. I don't have your full code, so this is not tested, but should give you an idea on how to do it.

If there was another child layer between your parent and the ListItem, I would definitely encourage using Redux. Personally I'm ok with passing references two levels deep using props for simple projects.

To get your ListItem values to show up in the parent input fields, make the following changes:

In your Parent:

// you need two-way data binding between state and input values
onChange(){
    this.setState({
      desc: this.refs.desc1.value,
      desc2: this.refs.desc2.value
    });
}

// this method will get triggered by ListItem's edit button onClick
onRowEdit(desc1, desc2){
    this.setState({
      desc: desc1,
      desc2: desc2
    });
}

render() {
        const headers = ["id","desc1", "desc2", "actions"];
        return(
            <div>
                <input ref="desc1" type = "text" placeholder = "Product Brand" value={ this.state.desc } onChange={this.onChange.bind(this)} />
                <input ref="desc2" type = "text" placeholder = "Product Brand" value={ this.state.desc2 } onChange={this.onChange.bind(this)/>
                <button type = "button" onClick = { this.handleSubmit.bind(this) }>Add</button>

                <CustomTable onEdit={ this.onRowEdit } mystate = { this.state } header = { headers } data = { this.props.store.productbrandlist }/>
            </div>
        )
    }

Your custom table renderRows:

renderRows(){
    // console.log("here1");
    // return(
    //  <ListItem datarows = { this.props.data }/>
    // )
    return this.props.data.map((list, id) => <ListItem onEdit={this.props.onEdit} mystate = {this.props.mystate} key_id={id} key={id} col = {list}/> )
}

Finally in your ListItem inside handleEditClick method call the function passed in the props:

handleEditClick(){
  // const desc1 = ... 
  // const desc2 = ...
  this.props.onEdit(desc1, desc2); // this call will cause desc1, desc2 values to show up in the parent's input fields.
}

Upvotes: 1

Related Questions