Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

React Inserting a compoent into a table between 2 rows dynamically

In React I have a table that lists rows of data and each row has a button that I want to
insert a row after it and add component that allows the user to fill inform data and click save and then delete the form row.

This is code that I have tried.

addRow = (idx) => {
    const table = document.getElementById("allocatorTable");
    const row = table.insertRow(idx + 1);
    row.className = "editorRow";
    const cell1 = row.insertCell(0);
    cell1.colspan = "10";
    cell1.appenChild(<TransactionRuleEditor />);
  };

Of course the <TransactionRuleEditor /> append wont work but it gives you the idea
of what i am trying to achieve.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

I have also tried adding the form to each row and hiding them. But of course you cant have more than one form on a page.

Any ideas plz?
Malcolm

>Solution :

When you’re using React (or any other MVC-like framework), you don’t work directly with the DOM like that, you take a different mindset: You change the state of what’s being rendered, and then the framework does the rendering. In this case, you might have the component providing the table row have a state where it actually provides two rows (wrapped in a fragment) when the button has been pressed.

Here’s a simplified exmaple:

const {useState, Component} = React;

class Row extends Component {
    constructor(props) {
        super(props);
        this.state = {
            adding: false,
        };
        this.onAdd = this.onAdd.bind(this);
        this.onDone = this.onDone.bind(this);
    }

    onAdd() {
        this.setState({adding: true});
    }

    onDone() {
        // (Obviously you'd do more here)
        this.setState({adding: false});
    }

    render() {
        const {adding} = this.state;
        const {data} = this.props;
        const row = <tr>
            <td>{data.a}</td>
            <td>{data.b}</td>
            <td>{data.c}</td>
            <td>{!adding &&
                <input type="button" onClick={this.onAdd} value="Add" />
            }</td>
        </tr>;
        if (!adding) {
            return row;
        }
        return <React.Fragment>
            {row}
            <tr>
                <td colSpan={3}>
                    The inputs go here.
                </td>
                <td>
                    <input type="button" onClick={this.onDone} value="Done" />
                </td>
            </tr>
        </React.Fragment>;
    }
}

// Or with hooks:
// const Row = ({data}) => {
//     const [adding, setAdding] = useState(false);
//     const row = <tr>
//         <td>{data.a}</td>
//         <td>{data.b}</td>
//         <td>{data.c}</td>
//         <td>{!adding &&
//             <input type="button" onClick={() => setAdding(true)} value="Add" />
//         }</td>
//     </tr>;
//     if (!adding) {
//         return row;
//     }
//     // (You might memoize the callbacks via `useCallback`)
//     return <React.Fragment>
//         {row}
//         <tr>
//             <td colSpan={3}>
//                 The inputs go here.
//             </td>
//             <td>
//                 <input type="button" onClick={() => /* Obviously you'd do more here */ setAdding(false)} value="Done" />
//             </td>
//         </tr>
//     </React.Fragment>;
// }

const Example = () => {
    const [items] = useState([
        {key: 1, a: "a1", b: "b1", c: "c1"},
        {key: 2, a: "a2", b: "b2", c: "c2"},
        {key: 3, a: "a3", b: "b3", c: "c3"},
    ]);
    return <table>
        <tbody>
            {items.map(item => <Row key={item.key} data={item} />)}
        </tbody>
    </table>;
};

ReactDOM.render(<Example />, document.getElementById("root"));
td {
    width: 70px;
}
<div id="root"></div>

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.development.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.development.js"></script>

(That example uses <React.Fragment> because the version of Babel in Stack Snippets is very out of date, but in your real code you can use <> instead.)

That’s just a sketch, of course. But it gives you an idea of how state can be used to handle this modality.

Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading