Todo MVC
In this guide you will learn how to develop a tipical Todo app using aria templates, taking advantage of his strong MVC orientation.
By referring to this guide, you will be able to:
- Put in practice the MVC pattern with aria templates.
- Use the aria templates DOM events (on keydown, on click, on blur).
- Use sections with repeater.
- Add and use listeners.
- Play with the refresh mechanism.
Tutorial
Step 1
Create a file using your favourite editor and call it index.html. This will be the bootstrap for your app.
Save it inside the root of your project (e.g. /guides/todo/).
Step 2
Insideindex.html you will have to load the aria templates framework, define the container div and load the template that you will create.
To load the framework:
<script type="text/javascript" src="/aria/css/atskin-1.2.0.js"></script>
To define the div container:
Aria.loadTemplate({
classpath:'ariadoc.guides.todo.view.Todo',
div:"output",
moduleCtrl: {
classpath : "ariadoc.guides.todo.TodoCtrl"
}
});
</script>
Step 3
Create a file and call it Todo.tpl. This is the template that will be used to display the Todo user interface.
Save it inside the view folder inside your project (/guides/todo/view/).
Step 4
Define the classpath of your template and that it has a script:$classpath: "ariadoc.guides.todo.view.Todo",
$hasScript: true
}}
<div>
<h1>Todos</h1>
{call listControl("markall")/}
{repeater {
id: "tasklist",
content: data.tasks,
type: "ul",
childSections: {
id: "task",
macro: "taskline",
type: "li",
bindRefreshTo: function(el) { return [ {inside:el.item} ] }
}
}/}
{call listControl("status")/}
</div>
{/macro}
Note: To get more info abour repeater take a look at this page.
Define the macro to manage the mark all tasks feature, the number of tasks left and the clear all completed tasks using a section with the refresh bound to the tasks inside the data model:* listControl
* --
* outputs list controls
* if type=markall the Mark All As bar is used
* if type=status the status bar is used
*/
{macro listControl(type)}
{section {
id: type,
type: "div",
attributes: {
classList: ["todo-"+type]
},
bindRefreshTo: [ {to:"tasks", inside:data} ]
}}
{if (data.tasks.length>0)}
{var t=this.moduleCtrl.tasksLeft()/}
{if (type=="markall")}
<label>
Mark all as completed
</label>
{elseif (type=="status")/}
<strong>${t}</strong> ${t>1 ? 'tasks':'task'} left.
{var c=data.tasks.length-t/}
{if (c>0)}
<a class="todo-clear">
Clear ${c} completed ${c>1 ? 'tasks':'task'}
</a>
{/if}
{/if}
{/if}
{/section}
{/macro}
Note: To get more info about sections take a look at this page.
Define the macro to manage the change of a task, displaying an input text to allow the user to update the task content and the icon to remove a task from the list:* taskLine
* --
* outputs a line in the list of tasks
*/
{macro taskline(el)}
{if (el.item.edit)}
<input type="text" class="editBox" {id "editBox"/} {on blur {fn:"leaveEdit", scope:this, args:el}/} {on keydown {fn:"editTask", scope:this, args:el}/} />
{else/}
<span>
<input type="checkbox" {if (el.item.done)}checked{/if} />
${el.item.desc}
<a class="remove" title="Remove this task"></a>
</span>
{/if}
{/macro}
Step 5
Create a file and call it TodoScript.js.
Save it inside the view folder inside your project (/guides/todo/view/).
Step 6
Define the classpath and the function scripts to manage the DOM events.Basically:
addTask: function(e)callsthis.moduleCtrl.addTask(v)inside the module controller;clearTask: function(e)callsthis.moduleCtrl.deleteTask(v)inside the module controller;markAll: function(e)callsthis.moduleCtrl.flagTask(i, checked)inside the module controller for each task;
The
clickTask() function marks a task or allows the user to change the text of the task clicked:
if (e.target.tagName.toUpperCase()=="INPUT") {
this.moduleCtrl.flagTask(el.index, !el.item.done);
} else {
aria.utils.Json.inject({edit:true}, el.item);
// the following is a tiny hack to put focus on the field and cursor at the end
var tf = this.$getElementById("editBox");
tf.focus();
tf.setValue(el.item.desc);
}
}
leaveEdit() function calls this.moduleCtrl.updateTask() function inside module controller to stop and resume the refresh to avoid extra refresh when the value changes:
// We use the RefreshManager stop() and resume() to avoid an extra refresh when the value changes
aria.templates.RefreshManager.stop();
this.moduleCtrl.updateTask(this.$getElementById("editBox").getValue(), el.index);
aria.utils.Json.deleteKey(el.item, "edit");
aria.templates.RefreshManager.resume();
}
Note: To get more info about the refresh manager take a look at this page.
Step 7
Create a file and call it ITodoCtrl.js.
Save it inside the root folder inside your project (/guides/todo/).
Step 8
Define the classpath, which class the controller interface extends, that is alwaysaria.templates.IModuleCtrl and write the signature of all the methods of your controller:
$classpath: "ariadoc.guides.todo.ITodoCtrl",
$extends: "aria.templates.IModuleCtrl",
$interface: {
tasksLeft: function() {},
addTask: function(desc) {},
updateTask: function(desc, idx) {},
deleteTask: function(idx) {},
flagTask: function(idx, done) {}
}
});
Step 9
Create a file and call it TodoCtrl.js.
Save it inside the root folder inside your project (/guides/todo/).
Step 10
Define the classpath, which class the controller extends, that is alwaysaria.templates.ModuleCtrl, which controller interface implements, in our case ariadoc.guides.todo.ITodoCtrl (that's the controller interface defined in the previous step) and define the constructor:
$classpath: "ariadoc.guides.todo.TodoCtrl",
$extends: "aria.templates.ModuleCtrl",
$implements: ["ariadoc.guides.todo.ITodoCtrl"],
$constructor: function () {
this.$ModuleCtrl.constructor.call(this);
this.setData({
tasks: (localStorage.tasklist ? JSON.parse(localStorage.tasklist) : [])
});
this.json.addListener(this._data, "tasks", {fn:this.__saveTasks, scope:this}, false, true)
}
Note: To read more about listeners take a look at this page.
Than the other functions:
tasksLeft: function()that just count the number of task left;addTask: function(desc)that callsthis.json.addto add a task to the todo list;updateTask: function(desc, idx)that callsthis.json.injectto update a task;deleteTask: function(idx)that callsthis.json.removeAtto remove a task from the todo list;flagTask: function(idx, done)that callsthis.json.setValueto mark a task as completed;__saveTasks: function()that saves the tasklisk inside the localStorage;
Step 11
Create a file and call it style.css.
Save it inside the root folder inside your project (/guides/todo/).
Step 12
Give some style to your todo app.
Step 13
That's it! Open the index.html with your favourite browser (e.g. Chrome) and enjoy.
