Milo TODO example
A TODO app made with Milo.js
by Jason Green
HTML
<script src="http://i.mol.im/cc/milo/237/dist/milo.bundle.js"></script>
<!-- An HTML input managed by a component with a `data` facet -->
<input ml-bind="[data]:newTodo" />
<!-- A button with an `events` facet -->
<button ml-bind="[events]:addBtn">Add</button>
<h3>To-Do's</h3>
<!-- Since we have only one list it makes sense to declare
it like this. To manage multiple lists, a list class
should be setup like this: ml-bind="MyList:todos" -->
<ul ml-bind="[list]:todos">
<!-- A single todo item in the list. Every list requires
one child with an item facet. This is basically milo's
ng-repeat, except that we manage lists and items separately
and you can include any other markup in here that you need. -->
<li ml-bind="Todo[item]:todo">
<!-- And each list has the following markup and child
components that it manages. -->
<input ml-bind="[data]:checked" type="checkbox">
<!-- Notice the `contenteditable`. This works, out-of-the-box
with `data` facet to fire off changes to the `minder`. -->
<span ml-bind="[data]:text" contenteditable="true"></span>
<button ml-bind="[events]:deleteBtn">X</button>
</li>
</ul>
<!-- This component is only to show the contents of the model -->
<h3>Model</h3>
<div ml-bind="[data]:modelView"></div>
CSS
/* Style for checked items */
.todo-item-checked {
color: #888;
text-decoration: line-through;
}
JavaScript
// Creating a new facetted component class with the `item` facet.
// This would usually be defined in it's own file.
// Note: The item facet will `require` in
// the `container`, `data` and `dom` facets
var Todo = _.createSubclass(milo.Component, 'Todo');
milo.registry.components.add(Todo);
// Adding our own custom init method
_.extendProto(Todo, { init: Todo$init });
function Todo$init() {
// Calling the inherited init method.
milo.Component.prototype.init.apply(this, arguments);
// Listening for `childrenbound` which is fired after binder
// has finished with all children of this component.
this.on('childrenbound', function() {
// We get the scope (the child components live here)
// It attaches components to DOM elements with ml-bind attribute
var scope = this.container.scope;
// And setup two subscriptions, one to the data of the checkbox
// The subscription syntax allows for context to be passed
scope.checked.data.on('', { subscriber: checkTodo, context: this });
// and one to the delete button's `click` event.
scope.deleteBtn.events.on('click', { subscriber: removeTodo, context: this });
});
// When checkbox changes, we'll set the class of the Todo accordingly
function checkTodo(path, data) {
this.el.classList.toggle('todo-item-checked', data.newValue);
}
// To remove the item, we use the `removeItem` method of the `item` facet
function removeTodo(eventType, event) {
this.item.removeItem();
}
}
// Milo ready function, works like jQuery's ready function.
milo(function() {
// Call binder on the document.
var scope = milo.binder();
// Get access to our components via the scope object
var todos = scope.todos // Todos list
, newTodo = scope.newTodo // New todo input
, addBtn = scope.addBtn // Add button
, modelView = scope.modelView; // Where we print out model
// Setup our...