I'm looking for a better solution for two things:
How can I understand if the data is fetched and ready, I use BasicDealList.on("reset", function(){})
to understand if the data is fetched from ajax and parsed and ready to be used but it feels dirty.
If an empty JSON comes from fetching such as {}
, it still shows BasicDealList.length as 1 while it should be 0 thus I was forced to check if the first element is empty via collection.length == 1 && jQuery.isEmptyObject(BasicDealList.toJSON()[0]
which is very ugly.
Here is the code:
BasicDeal = Backbone.Model.extend();
BasicDealCollection = Backbone.Collection.extend({
model: BasicDeal,
url: '/some/ajax/url/',
});
BasicDealList = new BasicDealCollection();
BasicDealList.on("reset", function(collection, response){
isEmpty = collection.length == 1 && jQuery.isEmptyObject(BasicDealList.toJSON()[0]);
if (isEmpty){
// render no deal found html
}
else{
// render list of deals
}
}
BasicDealList.fetch();
If you don't like listening for reset
, you can pass a callback directly to .fetch()
:
BasicDealList.fetch({
success: function(collection, response){
// ...
}
});
If, later in your app, you want to know whether you've fetched the data already, you could usually just check BasicDealList.length
. If you want to avoid making repeated requests for collections that are actually empty on the server, you'll probably need to work out a custom solution, e.g. setting a flag on .fetch()
:
BasicDealList.fetch({
success: function(collection, response){
BasicDealList.fetched = true;
// ...
}
});
As for the empty data issue, you should be returning []
from the server instead of {}
. Backbone's Collection calls this.add(models, ...)
within .reset()
, and .add()
checks whether the models
argument is an array; if it's not, it wraps it in one:
models = _.isArray(models) ? models.slice() : [models];
So passing {}
will result in models
set to [{}]
, which is not what you want. If you can't control the server, you could do the check for {}
in a custom .parse()
method, returning []
if it's found.
I know this question has already been answered but here is an alternative.
BasicDealCollection = Backbone.Collection.extend({
model: BasicDeal,
url: '/some/ajax/url/',
});
myCollection = new BasicDealCollection()
deferred = myCollection.fetch()
$.when(deferred).then(function() {
// do stuff when we have the data.
});
The key benefit of this is that we are using the "when" function. The "when" function gives us the ability to check multiple fetch calls and do one success.
$.when(deferredOne, deferredTwo, deferredThree).then(function() {
// do stuff when we have the data.
});
Also, if we stored the deferred object into a variable, we can do things like this. The variable will be a flag to let us know that we already loaded the data.
if (deferred.state() === "resolved") {
// do stuff when we have the data.
}
When we call fetch() on a collection it returns a jQuery deferred object. A jQuery deferred object can be in 3 states, "pending", "rejected" or "resolved" and once we have the data, it will set the state of the deferred object to resolved.
We needed a way to tell if a RelationalModel's relation had been fetched or not. This is our solution (in Coffeescript).
initialize: (objects, options) ->
@fetched = false
@listenTo @, 'sync', -> @fetched = true
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With