kuba_ceg
kuba_ceg

Reputation: 930

React + MaterialUi handling actions in IconMenu and ListItem

I'm learning react and I try to create simple TODO based on material-ui, I have problem with handling IconMenu menu actions, menu is displayed in listItem element. At this moment I have no idea how trigger deleteItem function with item name as a parameter when delete action is clicked in menu.

const iconButtonElement = (
    <IconButton touch={true} tooltip="More" tooltipPosition="bottom-left">
        <MoreVertIcon color="black"/>
    </IconButton>
);

const rightIconMenu = (
    <IconMenu iconButtonElement={iconButtonElement}>
        <MenuItem value="done" leftIcon={<Done />}>Mark as done</MenuItem>
        <MenuItem value="delete" leftIcon={<Delete />}>Delete</MenuItem>
    </IconMenu>
);

class TodoElements extends Component {
    deleteItem(nameProp)
    {
        this.props.delete(nameProp);
    }
    render() {
        var listItemRender = function(item) {
            return <ListItem key={item.name} primaryText={item.name} style={listItemStyle} rightIconButton={rightIconMenu}/>
        };
        listItemRender = listItemRender.bind(this);
        return (
            <List>
                {this.props.items.map(listItemRender)}
            </List>
        )
    }
}

Upvotes: 0

Views: 1308

Answers (2)

Matan Bobi
Matan Bobi

Reputation: 2813

I think that a nicer approach would be using the onTouchTap every MenuItem has, So the onChange function won't have a switch or many if statements. I'm actually using it when I iterate over all menu items, To me it looks like this:

                        _.map(menuItems, (currItem, index) => {
                        return (<MenuItem primaryText={currItem.primaryText}
                                          rightIcon={currItem.rightIcon}
                                          leftIcon={currItem.leftIcon}
                                          key={`menu-item-${index}`}
                                          value={currItem.value}}
                                          onTouchTap={currItem.onTouchTap}/>)
                    })

Upvotes: 0

Nikolaj Dam Larsen
Nikolaj Dam Larsen

Reputation: 5684

As far as I can see, you should be able to add an onChange handler to your IconMenu. So your rightIconMenu can look like this:

const RightIconMenu = ({onChange}) => (
    <IconMenu iconButtonElement={iconButtonElement} onChange={onChange}>
        <MenuItem value="done" leftIcon={<Done />}>Mark as done</MenuItem>
        <MenuItem value="delete" leftIcon={<Delete />}>Delete</MenuItem>
    </IconMenu>
);

Then you can use it in your TodoElements like this:

class TodoElements extends Component {
    constructor(props){
        super(props);

        this.state = {
            items: props.items
        };
    }

    createChangeHandler = (nameProp) => {
        return (event, value) => {
            if(value==="delete"){
                this.deleteItem(nameProp);
            }
        };
    }

    deleteItem = (nameProp) =>
    {
        this.setState({ 
            items: this.state.items.filter((item) => {
                return item.name !== nameProp);
            })
        });
    }

    render() {
        return (
            <List>
            {this.state.items.map((item) => {
                <ListItem key={item.name} primaryText={item.name} style={listItemStyle} 
                    rightIconButton={<RightIconMenu onChange={this.createChangeHandler(item.name)} />}/>
            })}
            </List>
        )
    }
}

Alternative

As an alternative solution you could bind an onClick handler to your delete MenuItem instead. I would probably implement it like this:

const RightIconMenu = ({onDelete}) => (
    <IconMenu iconButtonElement={iconButtonElement}>
        <MenuItem value="done" leftIcon={<Done />}>Mark as done</MenuItem>
        <MenuItem value="delete" leftIcon={<Delete />} onClick={onDelete}>Delete</MenuItem>
    </IconMenu>
);

And then replace the appropriate functions in the TodoElements:

createChangeHandler = (nameProp) => {
    return (event, value) => {
        this.deleteItem(nameProp);
    };
}
render() {
    return (
        <List>
        {this.state.items.map((item) => {
            <ListItem key={item.name} primaryText={item.name} style={listItemStyle} 
                rightIconButton={<RightIconMenu onDelete={this.createDeleteHandler(item.name)} />}/>
        })}
        </List>
    )
}

As for handling the state of your list of items, you should probably take a look at global state management such as Redux.

Upvotes: 1

Related Questions