Basic Todo List

Take a step deeper, make a basic todo list.

Alright, on to the actual Falcon tutorial. As you can see, the code written with Knockout, although very dynamic, doesn't have much structure or organization around it. This can lead to a large mess of code as a project grows from being a very simple application. This is where Falcon steps in. It adds structure to Knockout so that you can have both well organized and easily maintainable code with the dynamics of Knockout.

To demonstrate how Falcon adds better organization to Knockout, we'll start with a traditional todo list example. Here you'll see how Falcon can be used to add, remove, and complete todos on a todo list. This also allows us to edit the title and description of the todo list. In these examples, I've written comments around areas of interest describing how everything is working in the code. Be sure to look through all of the tabs in the jsFiddle to get a full understanding of everything.

A few key things to pay attention for are Models, Collections, Views, the Falcon.apply() method, and the $view binding context (in the html template).

Show Comments Hide Comments
 1 var Todo = Falcon.Model.extend({
 2 	url: 'todo',
 3 
 4 	observables: {
 5 		'text': '',
 6 		'is_complete': ''
 7 	}
 8 });
 9 
10 var Todos = Falcon.Collection.extend({
11 	model: Todo
12 });
13 
14 var TodoListView = Falcon.View.extend({
15 	url: '#todo_list_tmpl',
16 	
17 	defaults: {
18 		'todos': function() { return new Todos; }
19 	},
20 	
21 	observables: {
22 		'title': 'Untitled List',
23 		'is_editting_title': false,
24 		'new_todo_text': ''
25 	},
26 	
27 	initialize: function(){},
28 
29 	addTodo: function()
30 	{
31 		var todo = new Todo({ text: this.new_todo_text() });
32 		
33 		// Append the todo to the end of the colleciton. Note: We didn't need 
34 		// to define a new Todo model, rather we could have instead passed in 
35 		// the todo model's data and the collection would have created the todo 
36 		// for us.
37 		this.todos.append( todo );
38 		
39 		// Reset the todo text.
40 		this.new_todo_text('');
41 	},
42 	
43 	// Method used to remove a specific todo. Because this will be bound by Knockout's 
44 	// 'click' binding, the specific todo is passed in as the first argument for us.
45 	removeTodo: function(todo)
46 	{
47 		this.todos.remove( todo );
48 	},
49 	
50 	// Method used to mark a todo as complete
51 	completeTodo: function(todo)
52 	{
53 		// The set method is used on this model to set the value of 'is_complete'. 
54 		// This is useful in the scenario that we might not know if the is_complete 
55 		// property is an observable or a primitive value.  In this instance calling 
56 		// todo.is_complete( true ) would yield the same result.
57 		todo.set('is_complete', true);
58 	},
59 	
60 	// Method used to start editting the list title
61 	editTitle: function()
62 	{
63 		this.is_editting_title( true );
64 	},
65 	
66 	// Method used to 'save' the list's title
67 	saveTitle: function()
68 	{
69 		this.is_editting_title( false );
70 	}
71 });
72 
73 //Initialize our app and the initial view
74 view = new TodoListView;
75 //This method is used to apply the bindings to a specific element (in this example
76 //the div with the id 'application'). If an element isn't given, Falcon will default
77 //to the body element.
78 Falcon.apply(view, "#application");
79 
80 //Lastly, add some initial mock todos
81 view.todos.append([
82 	{'text': 'My First Todo'}, //Same as 'new Todo({...})'
83 	{'text': 'My Second Todo'},
84 	{'text': 'My Third Todo'}
85 ]);
Application Javascript
 1 <!DOCTYPE html>
 2 <html>
 3 	<head>
 4 		<script src="knockout-3.1.0.js"></script>
 5 		<script src="falcon.min.js"></script>
 6 		<script src="application.js"></script>
 7 	</head>
 8 	<body>
 9 		<div id="application"></div>
10 		<template id="todo_list_tmpl">
11 			<!-- ko if: $view.is_editting_title -->
12 				<input type="text" data-bind="value: $view.title" />
13 				<button data-bind="click: $view.saveTitle">Save</button>
14 			<!-- /ko -->
15 			<!-- ko ifnot: $view.is_editting_title -->
16 				<h3>
17 					<!-- ko text: $view.title --><!-- /ko -->
18 					<a data-bind="click: $view.editTitle">Edit</a>
19 				</h3>
20 			<!-- /ko -->
21 			<ul class="todo-list" data-bind="foreach: $view.todos">
22 				<li data-bind="css: {'completed': is_complete}">
23 					<!-- ko text: text --><!-- /ko -->
24 					<a data-bind="click: $view.completeTodo">[Complete]</a>
25 					<a data-bind="click: $view.removeTodo">[X]</a>
26 				</li>
27 			</ul>
28 			<input type="text" data-bind="value: $view.new_todo_text" />
29 			<button data-bind="click: $view.addTodo">Add</button>
30 		</template>
31 	</body>
32 </html>
Application HTML