Implement Pull‑to‑Refresh in a Titanium Alloy TableView
Add a built‑in RefreshControl to a TableView, bind data, and handle the refresh callback so the spinner appears on pull and hides after data reloads.
29 Jun 2026, 09:57 UTC

Desired outcome
When the user pulls down on a list, a refresh spinner appears, a handler runs to reload data, and the spinner disappears once the async operation finishes. The list should show the updated rows.
Prerequisites
- Titanium SDK 8.0 or newer installed.
- An Alloy project with a controller and view (e.g.,
index.jsandindex.xml). - A data source ready – this can be a simple array, a Backbone collection, or a mock service.
- Basic familiarity with Alloy controllers, views, and the
$.namespace.
Procedure
1. Define the TableView with a RefreshControl in the view
Open the view file (index.xml) and add a <TableView> that contains a <RefreshControl>. Assign an id to the TableView so the controller can reference it.
<Alloy>
<Window class="container">
<TableView id="list">
<RefreshControl onPull="doRefresh"/>
</TableView>
</Window>
</Alloy>
2. Bind data to the TableView in the controller
In the controller (index.js) initialize the data array and assign it to the TableView’s data property. For demonstration we use a static array of objects; replace this with your real data source.
// index.js
function initData() {
return [
{title: 'Item 1', properties: {height: 50}},
{title: 'Item 2', properties: {height: 50}},
{title: 'Item 3', properties: {height: 50}}
];
}
$.list.data = initData();
function doRefresh(e) {
// Simulate async work – replace with actual HTTPClient or model fetch
setTimeout(function () {
// Update the data source – here we just prepend a new item
var newItem = {title: 'New Item ' + ($.list.data.length + 1), properties: {height: 50}};
$.list.data = [newItem].concat($.list.data);
// Hide the spinner
$.list.refreshControl.endRefreshing();
}, 1500);
}
// Optional cleanup
$.addEventListener('close', function () {
$.removeEventListener('close', arguments.callee);
});
3. Test the refresh control
Run the application on an iOS simulator and an Android emulator or device. Pull down on the list; you should see the spinner appear, the timeout execute, the new row appear at the top, and the spinner disappear after 1.5 seconds.
Expected checks
- Visual: the refresh control appears as a spinning indicator when the list is pulled down.
- Log: add
Ti.API.info('Refresh started');at the start ofdoRefreshand verify it appears in the console. - Data: after the timeout, the TableView shows the newly added row.
- Hide: the spinner disappears once
endRefreshing()is called.
Recovery options and limitations
- Android API level: the built‑in
RefreshControlrequires API 21+. On older devices the control is ignored; provide a fallback such as a manual "Refresh" button in the view. - UI thread blocking: never perform heavy work directly in
doRefresh. UsesetTimeout,HTTPClientcallbacks, or promises to keep the UI responsive. - Memory leaks: remove any listeners you add manually in the controller’s
closeordestroyhandler. - Failure handling: wrap the async operation in a try/catch; in the catch block call
$.list.refreshControl.endRefreshing()and show an alert or toast to inform the user.
To verify the fallback on pre‑Lollipop Android, run the app on an emulator with API 19 and confirm that the pull gesture does not show a spinner but the manual button (if added) still triggers the refresh logic.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.