API Development

Update User Interface Elements Using Alloy & Backbone

If you’re developing apps in Titanium and Alloy, you’ve probably used the Backbone to bind collections and models to Tables, ListViews, Views and other elements. If you haven’t check it out.

Alloy data-binding is awesome — it’s easy to do and you can achieve in a few lines of code what would have taken many more in “Classic“ Titanium.

For the purposes of this article, I’m using a TableView as an example. It’s better to use a ListView in most cases for performance reasons, but it’s easier to explain this using a TableView.

In a simple Todo style Alloy application, you might have something like this:

<Alloy>
<Collection src="tasks" />
<Window>
<TableView dataCollection="tasks">
<TableViewRow title="{description}"/>
</TableView>
</Window>
</Alloy>

In this example, the collection tasks will be bound to the TableView automatically. If you were to change the name of a model in the collection, it’ll automatically refresh and update in the TableView — no additional is code required.

But, there’s more to this than just binding text and values. Let’s imagine that our model supports a .completed property that can be true or false and we’d like to show this in the list by displaying a tick if the task has been completed.

All we need to do this use the hasCheck property of the TableViewRow like this:

<TableViewRow title="{description}" hasCheck="{compeleted}"/>

Now when the view loads, anything with completed set to true, will render a check against the item in the list.

If the value of completed is changed in the model like this:

model.set("completed",false);

the check will disappear.

We can go further than this — let’s assume we want to add a custom graphic to show something is completed — how would we go about that?

Again, it’s straight-forward. Firstly, let’s rework the TableViewRow to make it a little easier:

<TableViewRow>
<Label left="10" text="{description}"/>
<ImageView right="10" image={statusImage}"/>
</TabelViewRow>

(For the purposes of simplicity, I’m using inline styles to position elements) — in practice, I’d move these into TSS classes.)

Next, let’s add the property dataTransform to the TableView:

<TableView dataCollection="tasks" dataTransform="transformTask">

The dataTransform property is now looking for a function called transformTask in the controller, so let’s add that:

function transformTask(model){
model = model.toJSON();
model.statusImage = model.completed ? "/images/tick.png" : "/images/cross.png"/>
return model;
}

This function accepts a model as a parameter, so the first thing we do is redefine it as a standard object by using the .toJSON method — this gives us a standard object to work with.

Once we have the object, we can additional properties or settings. At this stage, we’re not changing the underlying model, just a JSON representation of it for display purposes.

In this example, a new property, statusImage is being set based on the value of completed, and points to an image of a tick or cross.

Finally, we return the transformed JSON object to be turned into a model and bound to the view.

When we load this view, the transformTask function will be called for each model in the collection, and statusImage will be updated to be the appropriate image based on the value of .completed.

Let’s finish this off and add a click handler, so that when someone clicks a task, we can toggle its state.

In the past, you may have done this by adding a click event to the TableViewRowand handling the updating of the control like that — a much easier way is to add it to the TableView itself and use the index property passed in the event to get the row index.

So, we need to modify the TableView tag:

<TableViewRow onClick="toggleTaskStatus">

Then we add the handler to the controller:

function toggleTaskStatus(e){
if (e.index) {
Alloy.Collections.tasks.at(e.index).set("completed", 
!Alloy.Collections.tasks.at(e.index).get("completed"); } }

That’s it — there’s nothing more to do.

Once you run the view and tap a row, it’ll flag as completed and the relevant image will appear.

Cool isn’t it?

I’ve used this technique to hide / show information, or to change colours of elements in a list of financial transactions. But, there’s lots more you can do.

For example, if you’re binding models to bind values to a detail view, you can make sections appear and disappear using this technique. So, if there was a value for “Delivery address same as billing” option, setting the model property to true or false could hide / show a view that has the additional address details!

It’s an incredibly powerful feature of Alloy data-binding that requires very little JavaScript, which means simpler, more maintainable code and less bugs!

You can see some of this in action in my sample Todo app.