Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Toggle background color of list on click react.js

I am trying to create a list which has following features.

  1. On hover change background color of the listItem.
  2. On Click change background color of a listItem.
  3. Toggle background color between clicked elements.[i.e. Only one element in the list can have clicked property]

I have executed onhover 1 and 2 features, but I am not able to implement the 3rd feature. Please help me to solve this problem.

Thanks in advance.

/** @jsx React.DOM */

   'use strict'

    var React = require('react')


    var ListItem = React.createClass({

        getInitialState: function() {
            return  {hover_flag: false, click_flag: false}
        },

        hoverEvent: function() {
            this.setState({hover_flag: !this.state.hover_flag})
        },

        clickEvent: function(){
            this.setState({click_flag: true})
        },

        render: function() {
            var liStyle = {
                /* some more class properties */
                background: '#cc181e',
            }

            if(this.state.hover_flag || this.state.click_flag) {
                liStyle['background'] = '#880000'
            }

            if(this.state.click_flag) {
                liStyle['background'] = '#880000'           
            }

            return (
                <li onClick={this.clickEvent} onMouseEnter={this.hoverEvent} onMouseLeave={this.hoverEvent} style={liStyle} key={this.props.name}>{this.props.name}</li>
            )
        }

    })


    module.exports = React.createClass({

        render: function() {

            var ulStyle = {
                padding: '0px',
                margin: '20px',
            }

            var link = {
                textDecoration: 'none',
                color: 'white',
                cursor: 'pointer'       
            }


            var list = this.props.data.map(function(data) {
                /*List of li elements */
                return <ListItem name={data.name} />
            })

            return (

                <ul style={ulStyle}>
                    {list}
                </ul>

            )
        }

    });
like image 965
Vamshi Kolanu Avatar asked Dec 12 '25 23:12

Vamshi Kolanu


1 Answers

Before looking at any code, think about the actual cause of the problem. In your current implementation, each ListItem maintains its own click_flag state. When one ListItem is clicked, it sets its own click_flag to true, but this does not trigger the other ListItems to reset their own click_flag to false. This is the cause of the problem. The solution is to pass the click_flag as a props from the parent to each ListItem. It is the parent's responsibility to ensure that only ListItem gets prop as true, while the others are false. Likewise, it is the ListItem's responsibility to notify the parent when it has been clicked via a callback props passed down from the parent.

So, the ListItem looks like:

var ListItem = React.createClass({
    propTypes: {
        onClick: React.PropTypes.func.isRequired,
        isSelected: React.PropTypes.bool
    },
    getDefaultProps: function() {
        return {
            isSelected: false
        };
    },
    getInitialState: function() {
        return {
            hover_flag: false
        };
    },
    hoverEvent: function() {
        this.setState({hover_flag: !this.state.hover_flag});
    },
    render: function() {
        var liStyle = {
            background: '#cc181e'
        };
        if (this.props.isSelected || this.state.hover_flag) {
            liStyle['background'] = '#880000';
        }
        return (
            <li
                onClick={this.props.onClick}
                onMouseEnter={this.hoverEvent}
                onMouseLeave={this.hoverEvent}
                style={liStyle}>{this.props.name}
            </li>
        );
    }
});

And, the parent could look like this:

module.exports = React.createClass({
    getInitialState: function() {
        return {
            selectedItem: null
        };
    },
    clickHandler: function(idx) {
        this.setState({selectedItem: idx});
    },
    render: function() {
        var ulStyle = {
            padding: '0px',
            margin: '20px'
        };
        var items = this.props.data.map(function (item, idx) {
            var is_selected = this.state.selectedItem == idx;
            return <ListItem
                key={item.name}
                name={item.name}
                onClick={this.clickHandler.bind(this, idx)}
                isSelected={is_selected}
                />;
        }.bind(this));
        return (
            <ul style={ulStyle}>
                {items}
            </ul>
        );
    }
});

The parent maintains the state variable which stores which ListItem is the current selected one. It uses this state in render() to pass is_selected = true to only one ListItem, and all the others are passed false. The parent's state is updated by the clickHandler which is passed down as a props to each ListItem. See example fiddle here

like image 56
FriC Avatar answered Dec 15 '25 11:12

FriC



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!