CanJS Tutorial
by donejs
HTML
<script src="http://canjs.com/release/2.0.1/can.jquery.js"></script>
<ul id='todos'></ul>
<input id='editor'/>
<script type='text/mustache' id='todosMustache'>
<!-- bind to changes in the todo list -->
{{#todos}}
<li {{data 'todo'}}>
<input type="checkbox" class="complete" {{#if complete}}checked{{/if}}/>
<span class="{{#if complete}}done{{/if}}">
{{name}}
</span>
<!-- a destroy link -->
<a href="javascript://" class='destroy'>X</a>
</li>
{{/todo}}
</script>
CSS
@import url(http://fonts.googleapis.com/css?family=Lato:100,400,700);
* {
font-family: 'Lato', sans-serif;
font-size: 16px;
text-shadow: 0 1px 0 #ffffff;
}
.done {
text-decoration: line-through;
color: #ccc;
}
li { padding: 5px; font-size: 18px; cursor: pointer;}
li:hover {
background-color: #eee;
}
.destroy {
background-color: #999;
color: #fff;
-webkit-border-radius: 20px;
-moz-border-radius: 20px;
border-radius: 20px;
text-decoration: none;
font-size: 8px;
padding: 2px 5px;
margin: 5px;
text-shadow: 0 -1px 0 #999;
}
.destroy:hover {
background-color: red;
}
#editor {
font-size: 18px;
margin: 5px;
}
JavaScript
// Setup the model to work with dummy todos because we don't have a service
// Only findAll and update are used.
var TODOS = [
{id: 1, name: "wake up", complete: true},
{id: 2, name: "take out trash", complete: false},
{id: 3, name: "do dishes", complete: false}
];
var Todo = can.Model.extend({
findAll : function(){
return $.Deferred().resolve(TODOS);
},
findOne : function(params){
return $.Deferred().resolve(TODOS[(+params.id)-1]);
},
update : function(id, attrs){
// update TODOS with the new attrs
$.extend(TODOS[id -1], attrs);
return $.Deferred().resolve()
},
destroy : function(){
return $.Deferred().resolve()
}
},
{});
can.route("todos/:id");
// Organizes a list of todos
var Todos = can.Control.extend({
// called when a new Todos() is created
"init" : function( element , options ){
// get all todos and render them with
// a template in the element's html
var el = this.element;
Todo.findAll({}, function(todos){
el.html( can.view('todosMustache', {todos: todos}) )
});
},
// when a todo is clicked, create a 'selected'
// event for others to listen to
"li click" : function(li){
li.trigger('selected', li.data('todo') );
},
// when .complete is clicked, mark the todo completed
"li .complete click" : function(el, ev){
el.closest('li')
.data('todo')
.attr('complete', el.prop('checked'))
.save();
ev.stopPropagation();
},
// when .destroy is clicked, destroy the
// todo
"li .destroy click" : function(el, ev){
el.closest('li')
.data('todo')
.destroy();
ev.stopPropagation();
}
});
// Editor manages editing a todo's name
// call update on the editor like
var Editor = can.Control.extend({
todo : function(todo){
this.options.todo = todo;
this.on();
this.setName()
},
// a helper that sets the value of the input
// to the todo's name
setName :...