Milo
Browser/nodejs reactive programming and data driven DOM manipulation with modular components
Install / Use
/learn @milojs/MiloREADME
Milo
Browser/nodejs reactive programming and data driven DOM manipulation with modular components.
Documentation: http://milojs.github.io/milo/
Quick start
Install
npm install milojs
or
bower install milo
Test
npm install
npm install -g grunt-cli
grunt test
To run all tests, including browser tests:
grunt tests
Try
index.html
<html>
<head>
<title>Binding example</title>
<script src="milo.bundle.js"></script>
<script src="index.js"></script>
</head>
<body>
<input type="text" ml-bind="[Data]:myField">
<div ml-bind="[Data]:myCurrentValue"></div>
<button ml-bind="[Events]:myTestButton">
Test
</button>
<div>
<span ml-bind=":myTestValue"></span>
</div>
<div>
<h2>I am connected:</h2>
<span ml-bind="[Data]:myTestValue2"></span>
</div>
</body>
</html>
index.js
// run when DOM is ready
milo(function () {
// create and bind components with milo.binder
var scope = milo.binder();
// attach subscriber to data change event via data facet
// of myField component
scope.myField.data.on('', function(msg, data) {
scope.myCurrentValue.data.set(data.newValue);
// alternatively:
// scope.myCurrentValue.el.innerHTML = data.newValue;
});
// attach subscriber to click event via events facet
// of myTestButton component
scope.myTestButton.events.on('click', function(msg, event) {
scope.myTestValue.el.innerHTML = scope.myField.data.value();
});
// connect two components directly via their data facets
// using milo.minder
milo.minder(scope.myField.data, '->', scope.myTestValue2.data);
});
Note on runtime parameter type checking
Milo uses check module (milo.util.check - forked from check package of Meteor framework) for runtime checking of parameter types. It is highly recommended to switch off this checks in production using: milo.config({ check: false }).
Depending on your application, it can improve performance more than twice.
Samples/Tutorials
Getting started
Article about creating milo Rolling Your Own Framework on tuts+
TodoMVC
The more advanced sample is Todos app in todomvc folder.
Contribute
cd $MILO_FOLDER
npm link
cd $MY_PROJECT
rm -R -f -d node_modules/milojs
npm link milojs # link milo to your current project to use with browserify
cd $MILO_FOLDER
grunt # rebuild milo bundle every time you change any .js file
Additionally you can setup grunt in your project to rebuild it whenever milo bundle changes.
Please make sure you run grunt tests before committing (not just grunt test that is run by TravisCI automatically) - it will run all tests, including browser tests.
Concepts
Modular design
Although milo is packaged as one bundle, it has very modular structure. It consists of several independent modules that can be used together or separately and that are designed to simplify common application tasks rather than to create any particular application structure.
Some modules in milo can be used only in browser (Component, ComponentFacet, milo.binder), some both in browser and in nodejs (Messenger and its related classes, Model, Connector, milo.minder).
Milo itself uses browserify to package bundle, but any modules system can be used in an app that uses milo - milo does not suggest any application structure.
Component
Component is designed to simplify the management of DOM. Component is attached to a certain DOM element. Attaching several components to the same DOM element is usually an application (or milo) design mistake, so if it happens an error will be logged to console.
Components allow very easy creation of subclasses that are defined as a collection of configured "facets". For example, see the definition of MLSelect UI component.
There is a Component template to simplify creation of your own components.
Component facet
ComponentFacet is a base class, subclasses of which group methods related to behaviours of components.
You would rarely need to instantiate a facet - when a component is created it creates all its facets
There are the following facets defined in milo:
- Container - a special facet that creates a scope of components
- Dom - a collection of helper methods simplifying DOM manipulation of component element
- Events - gives a convenient API to subscribe to DOM events
- Data - an api to manipulate DOM tree inside component element as data, allowing both getting/setting structured data from/to many DOM elements at once and creating reactive data connection of Models (see below) to DOM.
- List and Item - allow creating lists in DOM from arays in your data. Component class using any of these facets require Data facet (will be added automatically) that should be used to get/set list data and to create reactive data connection.
- Template - simplifies rendering of component DOM element from template.
- Css - Allows you to bind DOM data, or models to css classes using declaritive rules in the facet config.
- Frame - manages sending/receiveing messages to/from iframe.
- Drag - allows easy management of draggable DOM elements.
- Drop - helps creating drop targets.
- Model - simple wrapper for milo Model (see below), helping to store data on component.
There is a Component facet template to simplify creation of your own facets. All facets of components should be subclasses of ComponentFacet.
DOM binding and creation of component instances
Instances of your components are usually created automatically when you call milo.binder based on information about components classes, facets and component name in ml-bind attribute (can be changed via milo.config).
To make your components available to milo their classes should be registered in components registry (milo.registry.components). If you define new facets, their classes should also be registered (in milo.registry.facets).
As registering of components and facets classes usually happens in the same module (file) that defines the class, you have to execute this module. If you use broserify for module management it is enough to use:
require('my_component');
in any other module that is executed or required.
Messenger
milo supplies internal messaging classes that can also be used for application needs. All facets in milo have an instance of Messenger attached to them that defines messaging api specific to the facet, in most cases connecting to some external source (usually DOM events).
Messenger instances use instances of MessageSource subclasses to connect to external sources and instances of MessengerAPI subclasses to create higher level internal messages and transform message data. This architecture allows creating an advanced functionality in just a few lines of code.
Model
milo
