NOTE: Work in progress..
Update your backend to support data ranges.
The first step is to enable your back-end to support retrieval by ranges. In this step we will demonstrate how to do this with the merb app we built in step-6.
Open the file tasks.rb under app/controllers in your merb app. Then replace the index function with the following.
def index
from = params[:from]
range_length = params[:length]
tasks = Task.all(:offset => from.to_i, :limit => range_length.to_i).map { |task| json_for_task(task) }
ret = { :content => tasks, :self => '/tasks' , :total => Task.count }
display ret
end
|
Now your merb app takes two extra parameters :from and :length to support range retrieval and returns the data range and the total number of tasks that are in the server.
Modify you dataSource to use an SparseArray
From the SC.SparseArray documentation:
“A SparseArray makes it easy for you to create very large arrays of data but then to defer actually populating that array until it is actually needed. This is often much faster than generating an array up front and paying the cost to load your data then.
Although technically all arrays in JavaScript are "sparse" (in the sense that you can read and write properties are arbitrary indexes), this array keeps track of which elements in the array have been populated already and which ones have not. If you try to get a value at an index that has not yet been populated, the SparseArray will notify a delegate object first giving the delegate a chance to populate the component.
Most of the time, you will use a SparseArray to incrementally load data from the server. For example, if you have a contact list with 3,000 contacts in it, you may create a SparseArray with a length of 3,000 and set that as the content for a ListView. As the ListView tries to display the visible contacts, it will request them from the SparseArray, which will in turn notify your delegate, giving you a chance to load the contact data from the server.”
Now that you understand what is an SparseArray add an arrayDelegate attribute to the dataSource and replace the fetch function with the following code:
arrayDelegate: null,
fetch: function(store, fetchKey, params) {
var ret = null;
if(!params.sparseArray) {
ret = SC.SparseArray.array();
ret.set('rangeWindowSize', 30);
}
else ret = params.sparseArray;
ret.delegate = this.arrayDelegate;
var url;
var action={};
var r= SC.Request.getUrl("tasks").set('isJSON', YES);
r.set('address', 'tasks?from='+params.start+'&length='+params.length);
r.notify(this, this.fetchDidComplete,
{
store: store,
fetchKey: fetchKey ,
storeKeyArray: ret,
start: params.start,
length: params.length
}
).send();
return ret;
},
|
The new fetch function creates a new sparseArray (first fetch) if is not passed in the params sets the arrayDelegate that will be explained later and builds the url to do a range retrieval.
We also need to replace the callback function fetchDidComplete. Copy & paste the following code:
fetchDidComplete: function(r,params) {
var hashes= [], storeKeys= [], store, fetchKey, ret, primaryKey,
response, results, lenresults, idx, total;
response = r.response();
if(response.kindOf ? response.kindOf(SC.Error) : false){
this.requestDidError(r);
}else{
fetchKey = params.fetchKey;
results = response.content;
total = response.total;
start = params.start;
length = params.length;
storeKeys = params.store.loadRecords(fetchKey, results);
params.storeKeyArray.provideLength(total);
params.storeKeyArray.replace(start,response.content.length,storeKeys);
params.storeKeyArray.rangeRequestCompleted(start);
}
return YES;
},
|
Now it sets the length of the array to be the total number of tasks in the server, replaces the unloaded records with the ones just fetched and notifies the array that the range request has been completed.
Now your apps support incremental loading of data. SparseArray and collectionview take control and do all the magic for you.
Comments (0)
You don't have permission to comment on this page.