Skip to content
chrismichaelscott edited this page Oct 21, 2013 · 24 revisions

If you're new to Iugo - the best place to get started is the tutorials page.

The Iugo constructor

The Iugo constructor is used to create an object which represents the supplied model except with listeners attached to handle updates to the model.

new Iugo(model, view, viewcontroller);

The Iugo constructor accepts three arguments (but is commonly only called with the first):

model:

  • Any Javascript Object representing the data model
  • Required!
  • Values which are not null will act as default values

For example:

var model = {
	id: 817,
	user: {
		name: "chris",
		dateOfBirth: "31st March 1984",
		address: {
			street: "1 Sesame Street",
			city: "London"
		}
	},
	friends: [
		"Bob",
		"Bill",
		"Ben",
		"Betty"
	],
	interests: {
		books: [
			{
				title: "20 thousand leagues under the sea",
				author: "Jules Verne",
				isbn: 92341
			}
		]
	}
};

View:

  • An element from the DOM
  • Will act as a scope for any view-controller actions
  • If omitted, document.body will act as the view

To limit the scope of the Iugo object to an element with the id "view" you would use:

var view = document.getElementById('view');

Viewcontroller:

  • An associative array of functions
  • For each top level member of the model, if an equivalent key exists, a function from the viewcontroller is executed when that part of the model is updated
  • The viewcontroller methods are passed a single argument, which is the new value assigned to the model's member
  • Plugins provide "default view-controllers" which handle actions such as binding the model to the DOM.

This view controller would log a message each time the "key" object was updated:

var viewcontoller = {
	key: function(value) {
		console.log("The key has been updated to " + value);
	}
};

HTML binding

There are two parts HTML binding. Firstly applying a class to an element of the form class="bindto-member". This will attach the content of model.member to that node in the DOM. In the case where model.member is a primitive type, you're done. If, however, model.member is an Object or an Array there are some additional steps.

<div class="bindto-id"></div>

will become

<div class="bindto-id>817</div>

To bind a value from an Object you can apply the attribute data-bind_key="path.to.value" to either the element in question or any children of that element. For each element with the attribute, model.member.path.to.value will be set as the innerHTML.

<div class="bindto-user">
    <span data-bind_key="name"></span>
</div>

will become

<div class="bindto-user">
    <span data-bind_key="name">Chris</span>
</div>

To bind the values from an Array to the DOM there is an additional attribute: data-bind_each. This must be applied to a child of the element with the bindto-member class. iugo will copy this node for each entry in the array, then process the new node as normal.

<ul class="bindto-friends">
    <li data-bind_each></li>
</ul>

will become

<ul class="bindto-friends">
    <li data-bind_each>Bob</li>
    <li data-iugo_cloned>Bill</li>
    <li data-iugo_cloned>Ben</li>
    <li data-iugo_cloned>Betty</li>
</ul>

Combining bind instructions

data-bind_key="path" attributes can be used on any element in the DOM tree under a node which has been bound with a bindto-member class. For example:

<div class="bindto-user" data-bind_key="address.city"></div>
<div class="bindto-interests">
    <ul data-bind_key="books">
        <li data-bind_each>
            <span data-bind_key="title"></span>
        </li>
    </ul>
</div>

Templating variables

As well as binding the whole innerHTML of a node, one can use an inline variable to inject values from the model into a page. Variables can be used both in the text of a document and in attributes of HTML tags.

The syntax has two variants, a simple flavour which is relative to it's closest bound parent and a namespaced flavour which lets one access any part of the model.

Simple variables

The simple flavour of variables is written as follows:

${relative.path}

This syntax addresses data relative to a bound node. So:

<div class="bindto-user">${name} lives in ${address.city}</div>

becomes:

<div class="bindto-user"><span data-bind_key="name">Chris</span> lives in <span data-bind_key="address.city">London</span></div>

Similarly, these variables can be placed inside attribute values:

<div class="bindto-user"><img src="/images/users/${name}" alt="${name}"></img></div>

becomes:

<div class="bindto-user"><img src="/images/users/Chris" alt="Chris"></img></div>

NB. iugo maintains an index of where attributes have been bound, so if you update the model - changing name to "Sam", for example - the attributes are updated to match.

Namespaced variables

There may be times when you need to access data from multiple areas in the model - so cannot rely upon relative paths. For example, if you wanted to create a link to the URL /Chris/wishlist/add?isbn=92341, you would not be able to use the simple flavour or variables. For this use-case, one can access data using a namespace, where the namespace refers to a top level member of the model and the address is relative to that. For example:

<ul class="bindto-interests" data-bind_key="books">
    <li data-bind_each>
        <a href="/${user:name}/wishlist/add?isbn=${isbn}"></a>
    </li>
</ul>

Accessing the current level of the model in nested bindings

Consider the following example:

<ul class="bindto-friends">
    <li data-bind_each />
<ul>

In that case, the name of each friend is bound to the innerHTML of the li. If you need a more complex DOM structure you will need to reference the current level of the model within the loop - i.e. a variable which points to the friend's name. That variable is addressed using a dot: ${.}.

<ul class="bindto-friends">
    <li data-bind_each>
        <a href="http://example.com/friend/${.}">See ${.}'s page</a>
    </li>
<ul>

Using aliases for tag attributes

There are some cases, primarily when referencing a URL, that bound attributes can cause issues. Consider the img tag example:

<div class="bindto-user"><img src="/images/users/${name}" alt="${name}"></img></div>

While this works effectively, the user may notice an exception in their browser's console if the browser tries to retrieve an image from "/images/users/${name}", getting a 404, before iugo has made the substitution. The browser will still pick up the correct image a fraction of a second later but developers don't like errors, do we?

So, for the benefit of a cleaning up those 404s, there is an alternative method of binding attributes. Any attribute which starts with the prefix data-iugo_alias- will bind to the attribute as if the prefix were dropped. So,

<div class="bindto-user"><img data-iugo_alias-src="/images/users/${name}" alt="${name}"></img></div>

Would still bind "/images/users/Chris" to the scr attribute but the browser would never see the unprocessed template in the src tag. Perfect!