Building a Reusable Data‑Bound List View in Appcelerator Alloy (Titanium SDK 9.x)
Step‑by‑step guide to create a Backbone‑based model, bind it to an Alloy TableView, fetch remote data, and verify live updates without a full rebuild.
07 Aug 2026, 08:38 UTC

Desired outcome
Create a reusable, data‑bound list view using Alloy MVC that displays a title and subtitle for each item, fetches JSON data at runtime, and updates instantly when the underlying collection changes.
Prerequisites
- Install the Titanium CLI (or use Titanium Studio) and ensure Titanium SDK 9.x is available.
- Create a new Alloy project:
titanium create my-list-app --type=alloy. - Navigate to the project folder:
cd my-list-app. - Basic familiarity with JavaScript, Backbone models, and XML view syntax.
Procedure
1. Define a Backbone model
Create app/models/item.js with a simple memory‑backed model that provides title and subtitle attributes.
exports.definition = {
config: { adapter: { type: 'memory' } },
extendModel: function(Model) {
return _.extend(Model, {
defaults: { title: '', subtitle: '' }
});
},
extendCollection: function(Collection) { return _.extend(Collection, {}); }
};
2. Create the view XML
Add app/views/list.xml containing a TableView with an ItemTemplate that binds the model fields to two labels.
<Alloy>
<TableView id="listView">
<ItemTemplate name="item">
<Label bindId="title" class="title"/>
<Label bindId="subtitle" class="subtitle"/>
</ItemTemplate>
</TableView>
</Alloy>
3. Style the labels (optional)
In app/styles/list.js you can add basic styling:
'.title': { font: { fontSize: 16, fontWeight: 'bold' } },
'.subtitle': { font: { fontSize: 14 }, color: '#666' };
4. Populate the collection in the controller
Create app/controllers/list.js to fetch JSON data, instantiate a collection of item models, and assign it to the view.
var collection = Alloy.createCollection('item');
function fetchData() {
var client = Ti.Network.createHTTPClient({
onload: function(e) {
try {
var data = JSON.parse(this.responseText);
// Expect data to be an array of objects with title/subtitle
data.forEach(function(obj) {
collection.add(obj);
});
// Bind collection to the TableView
$.listView.setData(collection.toArray());
} catch (err) {
Ti.API.error('Failed to parse JSON: ' + err);
}
},
onerror: function(e) {
Ti.API.error('Network error: ' + e.error);
},
timeout: 10000
});
client.open('GET', 'https://example.com/api/items');
client.send();
}
// Defer fetch to avoid blocking UI init
setTimeout(fetchData, 0);
// Optional: handle row clicks
$.listView.addEventListener('click', function(e) {
var model = e.section.getItemAt(e.itemIndex);
alert('Clicked: ' + model.title);
});
exports.destroy = function() {
// Clean up listeners if needed
};
5. Open the view from the default controller
In app/controllers/index.js replace the default content with the list view:
var listWin = Alloy.createController('list').getView();
listWin.open();
Expected checks
- Build and run the app on an iOS simulator or Android emulator:
titanium build --platform ios --device-id <simulator-id>(or--platform android). - Verify that each row displays the
titleandsubtitlefrom the fetched JSON. - Inspect the device log (
titanium logor Logcat) for absence ofWARNorERRORtags related to binding, missing IDs, or failed network requests. - Programmatically add a model after launch (e.g., via the console:
Alloy.createController('list').getView().children[0].getData().push({title:'Test', subtitle:'Item'})) and confirm the list updates instantly without a full rebuild or flicker. - Tap a row and ensure the click handler fires (alert or log).
Recovery options
If the build fails or the UI does not appear as expected:
- Remove compiled assets:
titanium clean. - Revert
tiapp.xmlto a known‑good version (keep a backup before editing). - Reload the UI without a full rebuild by replacing the current window’s content:
var win = Alloy.createController('list').getView(); win.open();(call this from the console or a debug button). - Ensure all UI updates occur on the main thread; move lengthy work out of the controller’s
initand usesetTimeoutor listen toTi.Appresume/pause events.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.