Commit 9803689b authored by Sindre Sorhus's avatar Sindre Sorhus

rAppid.js app clenup and improve readme

parent 89083b70
<?xml version="1.0"?>
<app:TodoClass xmlns="http://www.w3.org/1999/xhtml"
xmlns:js="js.core" xmlns:ui="js.ui" xmlns:app="app" xmlns:view="app.view" xmlns:conf="js.conf"
xmlns:data="js.data">
<!-- LOCAL STORAGE CONFIGURATION -->
<data:LocalStorageDataSource cid="dataSource" name="todo-rappidjs">
<conf:Configuration path="todos" modelClassName="app.model.Todo"
collectionClassName="app.collection.TodoList"/>
</data:LocalStorageDataSource>
xmlns:js="js.core" xmlns:ui="js.ui" xmlns:app="app" xmlns:view="app.view" xmlns:conf="js.conf"
xmlns:data="js.data">
<!-- LOCAL STORAGE CONFIGURATION -->
<data:LocalStorageDataSource cid="dataSource" name="todo-rappidjs">
<conf:Configuration path="todos" modelClassName="app.model.Todo"
collectionClassName="app.collection.TodoList"/>
</data:LocalStorageDataSource>
<!-- ROUTER CONFIGURATION -->
<js:Router cid="router">
<conf:Route name="default" route="^$" onexec="showAll"/>
<conf:Route name="active" route="^active$" onexec="showActive"/>
<conf:Route name="completed" route="^completed$" onexec="showCompleted"/>
</js:Router>
<!-- ROUTER CONFIGURATION -->
<js:Router cid="router">
<conf:Route name="default" route="^$" onexec="showAll"/>
<conf:Route name="active" route="^active$" onexec="showActive"/>
<conf:Route name="completed" route="^completed$" onexec="showCompleted"/>
</js:Router>
<!-- HERE WE START TO DEFINE THE UI WITH HTML AND CUSTOM UI COMPONENTS -->
<section id="todoapp">
<header id="header">
<h1>Todos</h1>
<input id="new-todo" placeholder="What needs to be done?" type="text" onkeyup="addNewTodo" autofocus="autofocus"/>
</header>
<section id="main" visible="{todoList.hasItems()}">
<input id="toggle-all" type="checkbox" onclick="markAllComplete"
checked="{todoList.areAllComplete()}"/>
<label for="toggle-all">Mark all as complete</label>
<!-- CUSTOM UI COMPONENT FOR RENDERING A LIST OF ITEMS -> TODOs -->
<ui:ItemsView items="{filterList.list}" tagName="ul" id="todo-list" itemKey="todo">
<js:Template name="item">
<view:TodoView todo="{$todo}" tagName="li" onremove="removeTodo"/>
</js:Template>
</ui:ItemsView>
</section>
<footer id="footer" data-num="{todoList.numOpenTodos()}" visible="{todoList.hasItems()}">
<span id="todo-count">
<strong>{data-num}</strong> {translateItems({data-num})} left
</span>
<ul id="filters">
<li>
<a href="#/" class="{selectedClass('all',{filterList.filter})}">All</a>
</li>
<li>
<a href="#/active" class="{selectedClass('active',{filterList.filter})}">Active</a>
</li>
<li>
<a href="#/completed" class="{selectedClass('completed',{filterList.filter})}">Completed</a>
</li>
</ul>
<button id="clear-completed" onclick="clearCompleted" visible="{todoList.hasCompletedTodos()}">
Clear completed ({todoList.numCompletedTodos()})
</button>
</footer>
</section>
<footer id="info">
<p visible="{todoList.hasItems()}">Double - click to edit a todo</p>
<p>Template by <a href="http://github.com/sindresorhus">Sindre Sorhus</a></p>
<p>
Created by <a href="http://github.com/krebbl">Marcus Krejpowicz</a> with<a href="http://rappidjs.com">&lt; rAppid:js/&gt;</a>
<br/>
Big credits to <a href="http://github.com/it-ony">Tony Findeisen</a>
</p>
<p>Part of
<a href="http://todomvc.com">TodoMVC</a>
</p>
</footer>
<!-- HERE WE START TO DEFINE THE UI WITH HTML AND CUSTOM UI COMPONENTS -->
<section id="todoapp">
<header id="header">
<h1>Todos</h1>
<input id="new-todo" placeholder="What needs to be done?" type="text" onkeyup="addNewTodo" autofocus="autofocus"/>
</header>
<section id="main" visible="{todoList.hasItems()}">
<input id="toggle-all" type="checkbox" onclick="markAllComplete"
checked="{todoList.areAllComplete()}"/>
<label for="toggle-all">Mark all as complete</label>
<!-- CUSTOM UI COMPONENT FOR RENDERING A LIST OF ITEMS -> TODOs -->
<ui:ItemsView items="{filterList.list}" tagName="ul" id="todo-list" itemKey="todo">
<js:Template name="item">
<view:TodoView todo="{$todo}" tagName="li" onremove="removeTodo"/>
</js:Template>
</ui:ItemsView>
</section>
<footer id="footer" data-num="{todoList.numOpenTodos()}" visible="{todoList.hasItems()}">
<span id="todo-count">
<strong>{data-num}</strong> {translateItems({data-num})} left
</span>
<ul id="filters">
<li>
<a href="#/" class="{selectedClass('all',{filterList.filter})}">All</a>
</li>
<li>
<a href="#/active" class="{selectedClass('active',{filterList.filter})}">Active</a>
</li>
<li>
<a href="#/completed" class="{selectedClass('completed',{filterList.filter})}">Completed</a>
</li>
</ul>
<button id="clear-completed" onclick="clearCompleted" visible="{todoList.hasCompletedTodos()}">
Clear completed ({todoList.numCompletedTodos()})
</button>
</footer>
</section>
<footer id="info">
<p visible="{todoList.hasItems()}">Double - click to edit a todo</p>
<p>Template by <a href="http://github.com/sindresorhus">Sindre Sorhus</a></p>
<p>
Created by <a href="http://github.com/krebbl">Marcus Krejpowicz</a> with<a href="http://rappidjs.com">&lt; rAppid:js/&gt;</a>
<br/>
Big credits to <a href="http://github.com/it-ony">Tony Findeisen</a>
</p>
<p>Part of
<a href="http://todomvc.com">TodoMVC</a>
</p>
</footer>
</app:TodoClass>
\ No newline at end of file
define(["js/core/Application", "js/core/I18n", "app/model/Todo", "app/collection/TodoList", "js/data/FilterDataView", "js/data/LocalStorageDataSource"],
function (Application, I18n, Todo, TodoList, FilterDataView, DataSource) {
define([
'js/core/Application',
'app/model/Todo',
'app/collection/TodoList',
'js/data/FilterDataView',
'js/data/LocalStorageDataSource'
], function ( Application, Todo, TodoList, FilterDataView, DataSource ) {
var ENTER_KEY = 13;
var ENTER_KEY = 13;
return Application.inherit("app.TodoClass", {
/**
* Initializes the app
* In this method we set the initial models
*/
initialize: function () {
this.set("todoList", null);
this.set("filterList", null);
this.callBase();
},
/**
* Are triggered
*/
showAll: function () {
this.$.filterList.set("filter", 'all');
},
showActive: function () {
this.$.filterList.set("filter", "active");
},
showCompleted: function () {
this.$.filterList.set("filter", "completed");
},
/**
* The rest is just controller stuff
*/
addNewTodo: function (e) {
if (e.domEvent.keyCode === ENTER_KEY) {
var title = e.target.get("value").trim();
if (title) {
var newTodo = this.$.dataSource.createEntity(Todo);
newTodo.set({title: title, completed: false});
this.get("todoList").add(newTodo);
return Application.inherit('app.TodoClass', {
/**
* Initializes the app
* In this method we set the initial models
*/
initialize: function() {
this.set( 'todoList', null );
this.set( 'filterList', null );
this.callBase();
},
/**
* Are triggered
*/
showAll: function () {
this.$.filterList.set("filter", 'all');
},
showActive: function () {
this.$.filterList.set("filter", "active");
},
showCompleted: function () {
this.$.filterList.set("filter", "completed");
},
/**
* The rest is just controller stuff
*/
addNewTodo: function (e) {
if (e.domEvent.keyCode === ENTER_KEY) {
var title = e.target.get("value").trim();
if (title) {
var newTodo = this.$.dataSource.createEntity(Todo);
newTodo.set({title: title, completed: false});
this.get("todoList").add(newTodo);
// save the new item
newTodo.save();
e.target.set('value','');
}
}
},
markAllComplete: function (e) {
this.get("todoList").markAll(e.target.$el.checked);
},
clearCompleted: function () {
this.get("todoList").clearCompleted();
},
removeTodo: function (e) {
var todo = e.$, self = this;
todo.remove(null, function(err){
if(!err){
self.get("todoList").remove(todo);
}
});
},
/**
* Start the application and render it to the body ...
*/
start: function (parameter, callback) {
this.set('todoList', this.$.dataSource.createCollection(TodoList));
// save the new item
newTodo.save();
e.target.set('value','');
}
}
},
markAllComplete: function (e) {
this.get("todoList").markAll(e.target.$el.checked);
},
clearCompleted: function () {
this.get("todoList").clearCompleted();
},
removeTodo: function (e) {
var todo = e.$, self = this;
todo.remove(null, function(err){
if(!err){
self.get("todoList").remove(todo);
}
});
},
/**
* Start the application and render it to the body ...
*/
start: function (parameter, callback) {
this.set('todoList', this.$.dataSource.createCollection(TodoList));
// fetch all todos, can be done sync because we use localStorage
this.$.todoList.fetch();
// fetch all todos, can be done sync because we use localStorage
this.$.todoList.fetch();
this.set('filterList', new FilterDataView({
baseList: this.get("todoList"),
filter: 'all',
filterFnc: function (item) {
var filter = this.$.filter;
if (filter == "active") {
return !item.isCompleted();
} else if (filter == "completed") {
return item.isCompleted();
} else {
return true;
}
}})
);
// false - disables autostart
this.callBase();
},
translateItems: function(num){
return (num === 1) ? "item" : "items";
},
selectedClass: function (expected, current) {
return expected == current ? "selected" : "";
}
});
});
\ No newline at end of file
this.set('filterList', new FilterDataView({
baseList: this.get("todoList"),
filter: 'all',
filterFnc: function (item) {
var filter = this.$.filter;
if (filter == "active") {
return !item.isCompleted();
} else if (filter == "completed") {
return item.isCompleted();
} else {
return true;
}
}})
);
// false - disables autostart
this.callBase();
},
translateItems: function(num){
return (num === 1) ? "item" : "items";
},
selectedClass: function (expected, current) {
return expected == current ? "selected" : "";
}
});
});
\ No newline at end of file
define(["js/data/Collection", "app/model/Todo", "flow"], function (Collection, Todo, flow) {
return Collection.inherit("app.collection.TodoList", {
$modelFactory: Todo,
return Collection.inherit("app.collection.TodoList", {
$modelFactory: Todo,
markAll: function (done) {
this.each(function (todo) {
todo.setCompleted(done);
todo.save();
});
},
areAllComplete: function () {
if (this.$items.length === 0) {
return false;
}
for (var i = 0; i < this.$items.length; i++) {
if (!this.$items[i].isCompleted()) {
return false;
}
}
return true;
}.on('change', 'add', 'remove'),
clearCompleted: function () {
var self = this;
// remove all completed todos in a sequence
flow().seqEach(this.$items,function (todo, cb) {
if (todo.isCompleted()) {
// remove the todo
todo.remove(null, function (err) {
if (!err) {
self.remove(todo);
}
cb(err);
});
} else {
cb();
}
}).exec();
},
numOpenTodos: function () {
var num = 0;
for (var i = 0; i < this.$items.length; i++) {
if (!this.$items[i].isCompleted()) {
num++;
}
}
return num;
}.on('change', 'add', 'remove'),
numCompletedTodos: function () {
var num = 0;
for (var i = 0; i < this.$items.length; i++) {
if (this.$items[i].isCompleted()) {
num++;
}
}
return num;
}.on('change', 'add', 'remove'),
hasCompletedTodos: function () {
return this.numCompletedTodos() > 0;
}.on('change', 'add', 'remove')
});
markAll: function (done) {
this.each(function (todo) {
todo.setCompleted(done);
todo.save();
});
},
areAllComplete: function () {
if (this.$items.length === 0) {
return false;
}
for (var i = 0; i < this.$items.length; i++) {
if (!this.$items[i].isCompleted()) {
return false;
}
}
return true;
}.on('change', 'add', 'remove'),
clearCompleted: function () {
var self = this;
// remove all completed todos in a sequence
flow().seqEach(this.$items,function (todo, cb) {
if (todo.isCompleted()) {
// remove the todo
todo.remove(null, function (err) {
if (!err) {
self.remove(todo);
}
cb(err);
});
} else {
cb();
}
}).exec();
},
numOpenTodos: function () {
var num = 0;
for (var i = 0; i < this.$items.length; i++) {
if (!this.$items[i].isCompleted()) {
num++;
}
}
return num;
}.on('change', 'add', 'remove'),
numCompletedTodos: function () {
var num = 0;
for (var i = 0; i < this.$items.length; i++) {
if (this.$items[i].isCompleted()) {
num++;
}
}
return num;
}.on('change', 'add', 'remove'),
hasCompletedTodos: function () {
return this.numCompletedTodos() > 0;
}.on('change', 'add', 'remove')
});
});
\ No newline at end of file
define(["js/data/Model"], function (Model) {
return Model.inherit("app.model.Todo", {
defaults: {
title: "",
completed: false
},
setCompleted: function (completed) {
this.set("completed", completed);
},
isCompleted: function () {
return this.$.completed;
},
status: function () {
return this.$.completed ? "completed" : '';
}.onChange("completed"),
hasTitle: function () {
return this.$.title.trim().length;
}.onChange("title")
});
return Model.inherit("app.model.Todo", {
defaults: {
title: "",
completed: false
},
setCompleted: function (completed) {
this.set("completed", completed);
},
isCompleted: function () {
return this.$.completed;
},
status: function () {
return this.$.completed ? "completed" : '';
}.onChange("completed"),
hasTitle: function () {
return this.$.title.trim().length;
}.onChange("title")
});
});
\ No newline at end of file
<ui:View xmlns="http://www.w3.org/1999/xhtml"
xmlns:js="js.core" xmlns:ui="js.ui" componentClass="{todo.status()}">
<js:Script>
<![CDATA[
(function () {
var ENTER_KEY = 13;
var INPUT_BLUR = "blur";
xmlns:js="js.core" xmlns:ui="js.ui" componentClass="{todo.status()}">
<js:Script>
<![CDATA[
(function () {
var ENTER_KEY = 13;
var INPUT_BLUR = "blur";
return {
defaults: {
editing: false
},
$classAttributes: ['todo', 'inputElement'],
events: ["remove"],
editTodo: function (e) {
this.set("editing", true);
e.preventDefault();
return {
defaults: {
editing: false
},
$classAttributes: ['todo', 'inputElement'],
events: ["remove"],
editTodo: function (e) {
this.set("editing", true);
e.preventDefault();
this.$.inputElement.$el.select();
return false;
},
checkTodo: function () {
var todo = this.get("todo");
todo.setCompleted(!todo.isCompleted());
todo.save();
},
preventEditing: function(e){
e.stopPropagation();
},
updateTodo: function (e) {
var todo;
if (e.domEvent.keyCode === ENTER_KEY || e.domEvent.type === INPUT_BLUR) {
todo = this.get("todo");
if (!todo.hasTitle()) {
this.trigger("remove", todo);
} else {
this.set("editing", false);
todo.save();
}
}
},
triggerOnRemove: function () {
this.trigger("remove", this.get("todo"));
},
_renderEditing: function (editing) {
if (editing) {
this.addClass("editing");
} else {
this.removeClass("editing");
this.$.inputElement.$el.blur();
}
},
trim: function(title){
if(title){
return title.trim();
}
return "";
}
this.$.inputElement.$el.select();
return false;
},
checkTodo: function () {
var todo = this.get("todo");
todo.setCompleted(!todo.isCompleted());
todo.save();
},
preventEditing: function(e){
e.stopPropagation();
},
updateTodo: function (e) {
var todo;
if (e.domEvent.keyCode === ENTER_KEY || e.domEvent.type === INPUT_BLUR) {
todo = this.get("todo");
if (!todo.hasTitle()) {
this.trigger("remove", todo);
} else {
this.set("editing", false);
todo.save();
}
}
},
triggerOnRemove: function () {
this.trigger("remove", this.get("todo"));
},
_renderEditing: function (editing) {
if (editing) {
this.addClass("editing");
} else {
this.removeClass("editing");
this.$.inputElement.$el.blur();
}
},
trim: function(title){
if(title){
return title.trim();
}
return "";
}
}
})
]]>
</js:Script>
<js:Template name="layout">
<div class="view" ondblclick="editTodo">
<input class="toggle" type="checkbox" onclick="checkTodo" ondblclick="preventEditing"
checked="{todo.completed}"/>
<label>{todo.title}</label>
<button class="destroy" onclick="triggerOnRemove"/>
</div>
<input class="edit" cid="inputElement" type="text" value="{{todo.title|trim()}}"
onkeyup="updateTodo" onblur="updateTodo" updateOnEvent="change"/>
</js:Template>
}
})
]]>
</js:Script>
<js:Template name="layout">
<div class="view" ondblclick="editTodo">
<input class="toggle" type="checkbox" onclick="checkTodo" ondblclick="preventEditing"
checked="{todo.completed}"/>
<label>{todo.title}</label>
<button class="destroy" onclick="triggerOnRemove"/>
</div>
<input class="edit" cid="inputElement" type="text" value="{{todo.title|trim()}}"
onkeyup="updateTodo" onblur="updateTodo" updateOnEvent="change"/>
</js:Template>
</ui:View>
{
"xamlClasses": ["app/Todo", "app/view/TodoView", "js/ui/ButtonGroup", "js/ui/Link", "js/ui/List", "js/ui/MenuButton", "js/ui/Modal", "js/ui/ScrollView", "js/ui/SplitButton", "js/ui/TabView"],
"namespaceMap": null,
"rewriteMap": null,
"paths": {
"xaml": "js/plugins/xaml",
"json": "js/plugins/json",
"raw": "js/plugins/raw",
"flow": "js/lib/flow",
"inherit": "js/lib/inherit",
"underscore": "js/lib/underscore",
"JSON": "js/lib/json2.js"
}, "shim": {
"inherit": {
"exports": "inherit"
},
"flow": {
"exports": "flow"
},
"underscore": {
"exports": "_"
},
"js/lib/parser": {
"exports": "parser"
},
"JSON": {
"exports": "JSON"
}
}}
\ No newline at end of file
"xamlClasses": [
"app/Todo",
"app/view/TodoView",
"js/ui/ButtonGroup",
"js/ui/Link",
"js/ui/List",
"js/ui/MenuButton",
"js/ui/Modal",
"js/ui/ScrollView",
"js/ui/SplitButton",
"js/ui/TabView"
],
"namespaceMap": null,
"rewriteMap": null,
"paths": {
"xaml": "js/plugins/xaml",
"json": "js/plugins/json",
"raw": "js/plugins/raw",
"flow": "js/lib/flow",
"inherit": "js/lib/inherit",
"underscore": "js/lib/underscore",
"JSON": "js/lib/json2.js"
},
"shim": {
"inherit": {
"exports": "inherit"
},
"flow": {
"exports": "flow"
},
"underscore": {
"exports": "_"
},
"js/lib/parser": {
"exports": "parser"
},
"JSON": {
"exports": "JSON"
}
}
}
\ No newline at end of file
.hide {
display: none;
display: none;
}
\ No newline at end of file
<!DOCTYPE HTML>
<html>
<!doctype html>
<html lang="en">
<head>
<title>TodoMVC build with rAppid.js</title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<link rel="stylesheet" href="../../../assets/base.css">
<!-- CSS overrides - remove if you don't need it -->
<link rel="stylesheet" href="css/app.css">
<!--[if IE]>
<script src="../../../assets/ie.js"></script>
<![endif]-->
<script type="text/javascript" src="package/rappidjs.min.js"></script>
<script type="text/javascript">
rAppid.bootStrap("app/Todo.xml", "config.json",
function (err, systemManager, application) {
if (!err) {
application.start(null, function () {
application.render(document.body);
});
} else {
console.warn(err);
}
});
</script>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>rAppid.js • TodoMVC</title>
<link rel="stylesheet" href="../../../assets/base.css">
<link rel="stylesheet" href="css/app.css">
<!--[if IE]>
<script src="../../../assets/ie.js"></script>
<![endif]-->
<script src="app/lib/rappidjs.min.js"></script>
<script>
rAppid.bootStrap( 'app/Todo.xml', 'config.json', function ( err, systemManager, application ) {
if ( !err ) {
application.start( null, function() {
application.render( document.body );
});
} else {
console.warn( err );
}
});
</script>
</head>
<body></body>
</html>
\ No newline at end of file
# Simple Todo App build with rAppid.js
# rAppid.js TodoMVC app
> rAppid.js is a declarative JavaScript web application for rapid web application development. It uses XML to define the structure of applications, modules, components and views and JavaScript for the business logic of the application. The XML (xaml) gets translated to javascript components during runtime which will render itself as HTML5 DOM elements. This enables a rapid development of applications.
This example app demonstrates the features and abilities of [rAppid.js](http://www.rappidjs.com)
This example app demonstrates the features and abilities of rAppid.js
## Documentation
### The index.html
### index.html
In the index.html the app is bootstrapped by defining our main app file (in this case Todo.xml). Because rAppid.js is a RIA framework, the whole rendering is done by JavaScript.
In the index.html the application is bootStrapped by defining our main application file
(in this case Todo.xml). Because rAppid.js is a RIA framework, the whole rendering is done by javascript.
If you are now thinking "yeah fine, but what about SEO", don't worry, rAppid.js also support Node-Rendering, which can be used for things like SEO.
If you are now thinking 'yeah fine, but what about SEO ', don't worry, rAppid.js also support Node-Rendering, which can be used for things like SEO.
### The application file Todo.xml
### Todo.xml
The main view of the application is declarated in Todo.xml. The first tag of the Todo.xml defines the super class of our application and the namespaces used inside the application description.
The main view of the app is declarated in Todo.xml. The first tag of the Todo.xml defines the super class of our app and the namespaces used inside the app description.
```xml
<?xml version="1.0"?>
<app:TodoClass xmlns="http://www.w3.org/1999/xhtml"
xmlns:js="js.core" xmlns:ui="js.ui" xmlns:app="app" xmlns:view="app.view" xmlns:conf="js.conf">
...
<app:TodoClass xmlns="http://www.w3.org/1999/xhtml" xmlns:js="js.core" xmlns:ui="js.ui" xmlns:app="app" xmlns:view="app.view" xmlns:conf="js.conf">
...
</app:TodoClass>
```
As you can see, the default namespace is `"http://www.w3.org/1999/xhtml"` which allows us to use plain HTML elements to describe our view.
The other namespaces are used for custom components.
As you can see, the default namespace is `"http://www.w3.org/1999/xhtml"` which allows us to use plain HTML elements to describe our view. The other namespaces are used for custom components.
One example of a custom component is the Router configuration.
```xml
<js:Router cid="router">
<conf:Route name="default" route="^$" onexec="showAll"/>
<conf:Route name="active" route="^active$" onexec="showActive"/>
<conf:Route name="completed" route="^completed$" onexec="showCompleted"/>
<conf:Route name="default" route="^$" onexec="showAll"/>
<conf:Route name="active" route="^active$" onexec="showActive"/>
<conf:Route name="completed" route="^completed$" onexec="showCompleted"/>
</js:Router>
```
Inside this declaration all routes of the application are defined. The **route** attribute expects a regular expression, which matches the route.
The **onexec** attribute defines the function which will be called, if the route is triggered.
The rest of the markup defines the UI of our application.
To connect the view with our application model we use bindings. For example the header:
All routes of the app are defined inside this declaration. The **route** attribute expects a regular expression, which matches the route. The **onexec** attribute defines the function which will be called, if the route is triggered.
The rest of the markup defines the UI of our app. To connect the view with our app model we use bindings. For example the header:
```html
<header id="header">
<h1>{i18n.translate('title')}</h1>
<input id="new-todo" placeholder="{i18n.translate('placeholder')}" type="text" onkeyup="addNewTodo"
value="{{newTodo.title}}" autofocus="autofocus"/>
</header>
<h1>{i18n.translate('title')}</h1>
<input id="new-todo" placeholder="{i18n.translate('placeholder')}" onkeyup="addNewTodo" value="{{newTodo.title}}" autofocus="autofocus"/>
</header>
```
The bindings tell the application to hold view and model in sync. If you're interested in more details, checkout the rAppid.js wiki.
The bindings tell the app to hold view and model in sync. If you're interested in more details, checkout the [rAppid.js wiki](http://www.rappidjs.com/#/wiki/Home).
### TodoClass.js
### The code behind file TodoClass.js
The TodoClass.js is the code behind file for Todo.xml. It initializes the attributes used in this application and it defines the event handlers for routing and ui events.
So there is a clean seperation between application code and ui declaration.
TodoClass.js is the code behind Todo.xml. It initializes the attributes used in this app and it defines the event handlers for routing and UI events. So there is a clean seperation between app code and UI declaration.
In the initialize method inside TodoClass all binded models are created and set as attributes of the application. This is important for resolving the bindings used in the view declaration.
In the initialize method inside TodoClass all bound models are created and set as attributes of the app. This is important for resolving the bindings used in the view declaration.
### The Todo Model (app/model/Todo.js)
### Todo Model (app/model/Todo.js)
The default attributes for an instance and some methods used inside the app are defined in this model.
In this model, the default attributes for an instance and some methods used inside the application are defined.
It also marks the functions `hasTitle` and `status` as bindable.
```javascript
status: function () {
return this.$.completed ? "done" : '';
}.onChange("completed"),
status: function() {
return this.$.completed ? 'completed' : '';
}.onChange('completed'),
```
Calling the `onChange(...)` function tells the application that the binding value of this methods has to be refreshed everytime the attributes change.
See app/view/TodoView.xml for usage.
### The Todo List (app/collection/TodoList.js)
The Todo List is a bindable List which encapsulates some application logic for manipulating the todo instances.
It also declares bindable functions, which are used inside the view ...
### The Todo View (app/view/TodoView.xml)
The Todo view is a custom view for displaying and editing Todo instances.
Here we define view logic and view declaration in one file.
Calling the `onChange()` function tells the app that the binding value of this methods has to be refreshed every time the attributes change. See app/view/TodoView.xml for usage.
### Todo List (app/collection/TodoList.js)
The Todo List is a bindable List which encapsulates some app logic for manipulating the todo instances. It also declares bindable functions, which are used inside the view.
### Todo View (app/view/TodoView.xml)
The Todo view is a custom view for displaying and editing Todo instances. Here we define view logic and view declaration in one file.
\ No newline at end of file
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment