Back to tutorials
  • 1Before We Start
  • 2Dependencies
  • 3Components
  • 4Configuring State
  • 5Rendering Data
  • 6Event Listeners
  • 7Updating State
  • 8Adding Todos
Metal.js HomeMetal.js
  • Documentation
Learn to create a simple Todo App with Metal.js and JSX

Event Listeners

Now you should have a static list of todo items. What now? Remember the end goal is to be able to click the todos to mark them as completed, so let's start with adding a click event listener to the list items:

// TodoItem.js

class TodoItem extends JSXComponent {
    render() {
        const elementClasses = `todo-item${this.props.todo.done ?
            ' todo-item-done' : ''}`;

        return (
            <li
                class={elementClasses}
                data-onclick={this.handleClick.bind(this)}
            >
                {this.props.todo.title}
            </li>
        );
    }

    handleClick(event) {
        alert(this.props.todo.title);
    }
}

Notice that the handleClick method has been bound to this. This is because you'll need to access instance properties inside the function. However, any JavaScript function can be passed as a handler, it doesn't have to be a method of the current class.

Now you should see an alert with the title of the clicked todo. Next you must notify TodoApp that a todo was marked as completed so that it can update the data. This can be done by emitting a custom event with the info needed to make the change. In this case we'll use the index value from PROPS:

// TodoItem.js

class TodoItem extends JSXComponent {
    ...

    handleClick(event) {
        this.emit('todoClick', {
            index: this.props.index
        });
    }
}

Now that the TodoItem is emitting an event, you must add a listener from the parent component TodoApp:

// TodoApp.js

class TodoApp extends JSXComponent {
    render() {
        return (
            <div class="todo-app">
                <ul>
                    {this.state.todos.map((todo, index) => {
                        return (
                            <TodoItem
                                events={{
                                    todoClick: this.handleTodoClick.bind(this)
                                }}
                                index={index}
                                todo={todo}
                            />
                        );
                    })}
                </ul>
            </div>
        );
    }

    handleTodoClick(event) {
        alert(event.index);
    }
}

At this point you should have an event handler that fires every time a todo item is clicked. Next you will use this data to update the state in TodoApp.

Alternative to custom events

Alternatively, you can pass functions from parents to children to achieve similar functionality. To do this, a child must declare a PROP to house the function from the parent:

class Parent extends JSXComponent {
    render() {
        return (
            <Child onChange={this.handleChange.bind(this)} />
        );
    }

    handleChange(event) {
        // Logic
    }
}

class Child extends JSXComponent {
    ...

    someMethod() {
        this.props.onChange({
            // Payload
        });
    }
}

Child.PROPS = {
    onChange: {
    }
}
I added the event listeners