Binding a Backbone Collection to a ListView in Titanium Alloy
Learn how to bind a Backbone collection to a Titanium Alloy ListView so the UI updates automatically when the data changes.
17 Sept 2025, 18:42 UTC

Quick answer
In Titanium SDK you can let Alloy’s MVC layers automatically keep a ListView in sync with a Backbone collection. Define a model and collection, declare an ItemTemplate in the view XML, and assign the collection’s data to the list in the controller. The framework then creates rows and updates them when the collection changes.
How it works – a worked example
Assume you want to show a simple list of items each with a title and subtitle.
1. Model definition
Create app/models/item.js:
exports.definition = {
config: {
adapter: {
type: 'memory'
}
},
defaults: {
title: '',
subtitle: ''
}
};
This tells Alloy to build a Backbone model with two string attributes.
2. Collection definition
Create app/collections/items.js:
exports.definition = {
config: {
adapter: {
type: 'memory'
}
},
extend: 'Backbone.Collection'
};
The collection will hold instances of the model defined above.
3. View XML with an ItemTemplate
Create app/views/list.xml:
<Alloy>
<ListView id="listView">
<ListSection>
<ItemTemplate name="item">
<Label bindId="title" text="{title}" left="10" top="5" />
<Label bindId="subtitle" text="{subtitle}" left="10" top="25" />
</ItemTemplate>
</ListSection>
</ListView>
</Alloy>
The {title} and {subtitle} bindings map directly to the model’s attributes.
4. Controller logic
Create app/controllers/list.js:
// fetch the collection (in this example we use the memory adapter)
var items = Alloy.Collections.items;
items.fetch();
// convert each model to a plain object for the ListView
var sectionItems = items.map(function(model) {
return { title: model.get('title'), subtitle: model.get('subtitle') };
});
// assign to the ListView
$.listView.sections = [Ti.UI.createListSection({ items: sectionItems })];
When the controller runs, the ListView displays rows built from the collection.
Limits and common mistakes
- Plain‑object requirement: Each item passed to
ListSectionmust be a plain JavaScript object with only string, number, or boolean values. Supplying a model instance, function, or nested object will be ignored and the row will appear empty. - Missing template or fetch: If you forget to define an
ItemTemplateor to callcollection.fetch(), the list will render with zero rows. - Large data sets: Rendering more than ~500 rows at once can cause UI jitter on older devices. Mitigate by enabling batch updates (
ListView.setItemswith a range) or using the built‑in paging support of the collection. - Memory leaks: Custom event listeners attached to list items (e.g.,
itemclick) should be removed when the controller is destroyed ($.destroy()) to prevent retained references.
Practical way to verify the binding
- Create a new Alloy project: run
alloy new ListDemoin a terminal (requires Titanium CLI installed). - Add the four files shown above (
models/item.js,collections/items.js,views/list.xml,controllers/list.js). - Build for a simulator or device, e.g.,
ti build -p ios -s simulator(or replaceioswithandroidand adjust the SDK target). - Launch the app. You should see a list of rows; because the memory adapter starts empty, you may want to add a few test models in the controller after
fetch():items.add([{title: 'First', subtitle: 'A'},{title: 'Second', subtitle: 'B'}]); - Open the device console (Xcode console for iOS, logcat for Android) or the Titanium Studio log view. Look for lines like
INFO: Collection fetch succeededand ensure there are no binding warnings such as "Unable to bind property undefined".
When to skip the collection
For static or very small data sets you can bypass the collection entirely and assign a plain array directly:
$.listView.sections = [Ti.UI.createListSection({ items: [
{title: 'Static', subtitle: 'Data'},
{title: 'Another', subtitle: 'Row'}
] })];
This avoids the overhead of Backbone events but loses automatic sync and event handling. Use the collection approach when the data may change after the initial render (e.g., from a remote API or user input).
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.