Anfal
Anfal

Reputation: 344

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;

Upvotes: 0

Views: 2057

Answers (1)

Andr&#233;s Andrade
Andr&#233;s Andrade

Reputation: 2223

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;

Upvotes: 2

Related Questions