A sparse array implementation to use in Ember.js projects. It automatically fetches items on-demand.
A common use-case is for extremely long lists, where it's not feasible to load all records into the browser.
When instantiating a SparseArray, you have to supply a load method. The load method is responsible for fetching
a subset of the resource, e.g. from your server.
The load method must accept two arguments:
offset: The 0-based index/offset of the first record to be fetched.limit: How many records should be fetched
The load method must return a thenable (i.e. a promise or another object with a .then method on it) that eventually
resolves with a hash with two keys:
total: The total number of records.items: An array of maximumlimititems that start atoffset.
Here is an example:
var SparseArray = require('sparse-array');
var comments = SparseArray.create({
load: function(offset, limit) {
return new Em.RSVP.Promise(function(resolve) {
$.getJSON('/comments?offset='+offset+'&limit='+limit).then(function(payload) {
resolve({
total: payload.meta.total,
items: payload.comments
});
});
});
}
});The SparseArray will automatically call your load method when items at not-yet-loaded indexes are being requested by
your application.
The length attribute of your SparseArray works just like a normal array. It will start out as 0. It will be set to
the value of total each time a promise from load resolves.
load is always called instantly with offset being 0 when you instantiate a SparseArray. This is to find the
length property right away.
The SparseArray also has a property called isLoaded, which is false until the first time a load completes,
where it will be set to true, and stay true forever.
Calling .objectAt at an index that's greater than or equals to the current length, will always return null.
Example:
var comments = SparseArray.create({
load: function(offset, limit) {/* ... */}
});
comments.get('length'); //Will always be 0, since the data hasn't been loaded yet
comments.get('isLoaded'); //false
comments.objectAt(0); //null
comments.objectAt(9999999); //null
//Later, after the first load has completed:
comments.get('length'); //The `total` value that you resolved the promise with
comments.get('isLoaded'); //true
comments.objectAt(0); //Whatever you returned at the index 0After the load method has completed at least once, and the array has a length property, requesting an index less
than length, will make the array fetch the items around that index using the load method, if the index has not
been loaded yet.
The {{each}} Handlebars helper is "eager", meaning that it will insert views for all items right away. So when your
load promise resolves with a total value of 9000, it will create 9000 views right away, and request each of the 9000
items from your array. This may result in a lot of requests.
The real power of sparse arrays is when using them together with container views that only requests (i.e. calls
.objectAt) items that is supposed to be in the browser's current viewport. A good example is
Ember.ListView (disclaimer: This sparse array implementation has not been tested
with Ember.ListView yet, but you get the idea).
You can set other options than the load method when instantiating SparseArray. Example:
SparseArray.create({
batchSize: 42,
load: function() {/* ... */}
});The following options are supported:
batchSize(integer): The maximum number of records the sparse array will ask theloadmethod to load through thelimitargument. The actual value oflimitmay be lower, since the sparse array will only load items that have not already been loaded. Defaults to100.
- Rejected promises from the
loadmethod are currently not handled.