Handle User Interaction
When a user does something, such as clicking, an event occurs. Event handlers specify
how JavaScript should respond to an event.
This recipe will introduce handling a click event using a can.Control.
Using a list of people like previous recipes, clicking any individual person's name
will remove that person from the list.
Previous examples have used jQuery's event handlers:
$("#push").click(function(){
//handle the event
});
CanJS provides a few different ways to respond to events. As well as making application code simpler, using CanJS to handle events can help to automatically prevent memory leaks.
To handle events, extend can.Control.
var PeopleList = can.Control.extend({
//behavior
});
You create a can.Control by calling it as a constructor function.
The first argument is the element the control will be created on.
The second argument is an object of options.
new PeopleList('#my-app', {people: people});
A can.Control handles events with functions declared with two arguments: an
element or list of elements (using a jQuery-style selector) and a specific event.
Below, this is 'li click', meaning when any li elements that are clicked the
function will be called to handle the click event.
var PeopleList = can.Control.extend({
init: function( element, options ){
this.people = new can.List(options.people);
this.element.html( can.view('app-template', {
//defines people in the template as the observable can.List
people: this.people
}));
},
'li click': function( li, event ){
//Handle the click event
}
};
When the constructor function is called and the can.Control
is instantiated:
- The
initmethod is called - An observable
can.Listis created frompeople - The list is rendered using
can.viewso when the list changes, so will the view
var people = [
{firstname: "John", lastname: "Doe"},
{firstname: "Emily", lastname: "Dickinson"},
{firstname: "William", lastname: "Adams"},
{firstname: "Stevie", lastname: "Nicks"},
{firstname: "Bob", lastname: "Barker"}
];
When the event handler for a click runs, it needs a way
to access the object associated with the li that was clicked.
With the data helper,
the element will retain a reference
to the object it is associated with (in this case, a person).
<ul>
{{#each people}}
<li {{data 'person'}}>
{{lastname}}, {{firstname}}
</li>
{{/each}}
</ul>
Finally, the event handler must be defined. In a can.Control,
an event handler function can be defined with a string containing
a selector and an event.
In this case, these are li and click, respectively,
since we want to handle click events on each list item.
var PeopleList = can.Control.extend({
init: function(){
...
},
'li click': function( li, event ) {
var people = this.people;
var person = li.data('person');
var index = people.indexOf(person);
people.splice(index, 1);
}
});
When a user clicks a list item:
- The function bound to
li clickis called - The object associated with that list item is accessed using the
datahelper - That 'person's data is removed from the observable list of
people - The template updates automatically
As a reminder, though event handlers respond to actions on the page,
they should change application state or data (e.g. make a change to a can.Map)
rather than modifying the DOM directly (e.g. toggling a class).
This will update the page automatically, keeping code manageable.
This is one way to handle events. Others will be covered in the following recipes while building widgets.