This page shows Test in action, simulating adding, editing, dragging, and deleting todos in the Todo List below. It also provides a walk through of the test code.
We'll walk through the Todo Demo application located in the navigation bar on the left. The Todo Demo allows you to add, remove, edit, and complete todos. Try it yourself before we begin. We'll cover the following steps:
If you'd like, download the demo and look through it yourself during or after this tutorial.
The following HTML displays the new todo form and one todo element. Notice the id 'todos' and the class 'todo'. In the next step we'll create a controller that works with these elements. This is what the page contains when it loads.
<div id="todos">
<form id="todo_form" class="new">
<input type="text" id="new_todo" value="new todo"/>
</form>
<div class="todo">
<img alt="close" src="../../images/close.png"/>
<input type="checkbox" class="check"/>
<label>Learn JavaScriptMVC</label>
<p class="clear"/>
</div>
</div>
The first step towards creating event handlers that respond to user interactions with the todo list HTML is creating a Todos Controller. To create this controller, we name it after the HTML elements we want to modify, in this case 'todos'. We name the controller 'todos' to cause its event handlers to respond to elements within the element with id 'todos'.
Controller('todos',{
When you mouse over the todo, notice how the background color changes to a darker shade of green. To add this color change effect, we'll add mouseover and mouseout event handlers. These will be called when a user mouses over or out of any element with class 'todo'. Params.element returns the element for which this event was triggered, in this case the todo element. We change the background color during mouseover and remove the background color during mouseout.
mouseover: function(params){
params.element.style.backgroundColor = '#8FBA3C';
},
mouseout: function(params){
params.element.style.backgroundColor = '';
},
Click a todo's text. You'll notice it is replaced by an input element, allowing you to edit the todo's content. To add this functionality, we want an input element to appear s when a user clicks the todo text. Our todo text is inside a label element within the div with class 'todo'. Naming our event handler 'label click' will attach this onclick handler to anything matching the CSS selector '.todo label'. In the event handler, we replace the text element with an input element and give it focus so we can start typing immediately.
'label click': function(params){
var input_element_html = '<input type="text" class="text" value="'+
params.element.innerHTML+'"/>';
if(params.element.childNodes[0].nodeType != 1)
params.element.innerHTML = input_element_html;
var input_element = params.element.firstChild;
// add focus to the input element
params.element.firstChild.focus();
params.element.className='working';
},
Type some text to edit a todo, then click out of the box. You'll notice the new todo is saved. The new text should remain when a user clicks out of the text input element, which is the blur event. The event is matched with 'label input', since the input element is inside the label element. We update the label's text with the value of the text input.
'label input blur': function(params){
// grab the label element
var label = params.element.parentNode;
// replace its text with the text from the input element
label.innerHTML = params.element.value;
label.className='';
},
After editing a todo, you can also click enter. You'll notice this has the same effect of saving the todo. Using the keypress event, we'll check to see if the key pressed had keyCode 13 (for Enter). If so, we'll call the blur event handler to re-use its functionality. IE uses the charCode attribute of the event object, but other browsers use the keyCode attribute, so we'll check for both.
'label input keypress': function(params){
var keyCode = params.event.keyCode;
if(typeof keyCode == 'undefined'){ //IE
if(params.event.charCode == 13) this['label input blur'](params);
}else if(keyCode == 13)
this['label input blur'](params);
},
Click the red delete button. You'll see this causes the corresponding todo to remove itself from the list. Since the delete button image is the only img element within each todo, we can assign it a click handler with the name 'img click'. In this handler, we use the class_element method to grab our todo and then remove it.
'img click': function(params){
var todo_element = params.class_element();
var containing_todos_element = todo_element.parentNode;
containing_todos_element.removeChild(todo_element);
},
When a user clicks the checkbox, we will make the todo's text gray to indicate its completion. Checkboxes have the class 'check', so we'll match these elements and assign them a click handler. Params.element returns the checkbox element that has been clicked. If its checked, we'll set the color to gray. Otherwise, we'll remove the color.
'.check click': function(params){
if(params.element.checked)
params.class_element().style.color = 'gray';
else
params.class_element().style.color = '';
},
The new todo input contains the text "new todo" to indicate its purpose. When you click this text box, you'll notice the text disappear, allowing you to add your own todo. To achieve this, we match this element with the selector '# .new input'. Controller expands this to '#todos .new input', which matches the input element inside the new todo form. When this element receives focus, we clear its value.
'# .new input focus': function(params){
params.element.value = '';
},
After you click away from the new todo input, the new todo is saved in the list. We want to attach an event handler to the blur event on the input element. We check to make sure the user has typed something, then we use Element.insert (part of the element plugin) to append the new todo after the 'todo_form' element. Finally, we set the input's value back to 'new todo'.
'# .new input blur': function(params){
// check the user has entered something
if(params.element.value != '' && params.element.value != 'new todo'){
var new_todo_html = "<div class='todo'>"+
"<img src='../../images/close.png' alt='close'/>";
new_todo_html += "<input type='checkbox' class='check'/><label>";
new_todo_html += params.element.value+"</label><p class='clear'> </p></div>";
// insert the new todo in the list
Element.insert('todo_form', {after: new_todo_html});
}
params.element.value = 'new todo';
},
Another way to create a new todo is to submit the form. We wrote the code for adding a new todo in the last event handler. Thus, we'll call the previous handler to avoid repeating functionality. We can match the new todo form with the selector '# form', since its the only form present in the 'todos' div element. First we need to set params.element to the input element, as the blur event handler above is expecting the input element as its element. We call kill() to stop the form submission event from propagating.
'# form submit': function(params){
params.element = $E('new_todo');
// the blur handler saves the new todo
this['# .new input blur'](params);
// stop the form submit event from propagating
params.event.kill();
params.element.value = '';
}
Overview
Controller's highlights.
API
Low level documentation for Controller's methods.
Learn
An explanation of important concepts and examples.