Models disappearing in backbone collection - backbone.js

I have code that does this
class MyCollection extends Backbone.Collection
initialize: ({some_id}) ->
super
#reset $.jStorage.get "mycollection:#{some_id}" # instant fetch
console.log #length # THE MODELS ARE THERE
my_collection = new MyCollection [], some_id: 123
console.log my_collection.length # THE MODELS ARE GONE

So, backbone's initialize function takes in any params and feeds it out as the models, use null instead of [] unless you are explicitally saying, "this blank array is definitely real data you should use", or if you somehow have an instant fetch, it will break
new MyCollection null, some_id: 123

Related

Backbone Model is a function?

I have the following function, which fails when called:
getAll: function() {
return _todos.toJSON();
}
_todos.toJSON is not a function it tells me.
Printing _todos gives me a function for some reason function child().
Why is that the case?
Here's my Backbone.Model:
var _todos = Backbone.Model.extend();
The getAll() function is sitting in my Collection:
var TodoCollection = Backbone.Collection.extend({
model: _todos,
getAll: ...
});
Edit:
I'm actually connecting Backbone with React, so that might change how I do this.
In addition to getAll I have this:
areAllComplete: function() {
return _.every(this.pluck('complete'), true);
}
An example I've been following seems to put getAll and areAllComplete in the Model and doesn't use Collection at all. I couldn't make sense of it, and since I want this to be restful down the road, I added the Collection and moved getAll and other one inside of it.
Perhaps, this is not what I want.
Edit 2:
According to a warning, the output of getAll is expected to be an Object not an array. I should probably add those function to Model not Collection. Need to think about this more.
I think this turned into another question...
The collection model property is used to specify what model class the collection contains and is used to create the proper models when you pass the raw data to your collection. Additionally based on your code if it did work you would have had a collection with just one model.
Aside from that in order to get the JSON of all the models in your collection you can call it's toJSON method
for example todoCollection.toJSON();
Or if you specifically want it in a getAll function (maybe you want to do something else before returning the data) you can do the following
var TodoCollection = Backbone.Collection.extend({
model: Todo,
getAll: function () {
//do something
return this.toJSON();
}
});
//here we are passing in the data directly, but you might get it with a fetch call
var todoStore = new TodoCollection(models);
var todosJson = todoStore.getAll();
Another thing to note is the backbone naming convention is to use PascalCase for classes and camelCase for instances .
That's because Backbone.Model.extend returns a constructor function. When you pass it to a collection via the model property you're just letting the collection know which kind of models it should hold.
To get the JSON for an entire collection, call toJSON() on the collection instance.
var collection = new TodosCollection();
// add models
collection.toJSON();
If you want JSON for one specific model then get a reference to it via the collection API (at, findWhere, get etc) and call toJSON() on that reference.
var model = collection.at(0);
model.toJSON();

An Array to Backbone Collection

I think this is a simple question. It is based of this question.
Filter and sort backbone collection with array of ids
router.on('route:reportCollection', function(assetid) {
var asset = assets.get(assetid);
var reportpointers = asset.get('reportsid');
var filteredReportCollection = new dilzeemQ.Collections.FilteredReportCollection({
});
ohhyearh = filteredReportCollection.filterById(reportpointers);
var reportCollectionView = new dilzeemQ.Views.ReportCollection({
collection: ohhyearh
});
console.log(ohhyearh);
console.log(reports);
$('#pagecontent').html(reportCollectionView.render().$el);
});
I have gotten it to work as I would like except the passing of the collection : ohhyearh
ohhyearh is something like this [child,child] where as I think it is expecting something along the lines of this {child,child}
At the point where you pass ohhyearh to the view, it should be an instanceof Backbone.Collection. That is what the view is expecting, not an array or an object with a property for each child.
Based on the code in the snippet, I would say that your filterById function is probably doing something unexpected and not returning an actual collection. You can either modify it to return new dilzeemQ.Collections.FilteredReportCollection(models) or you can leave it as is, and create a new collection when you pass it to the view:
collection: new dilzeemQ.Collections.FilteredReportCollection(ohhyearh)
This is assuming that your ohhyearh object is an array with Backbone.Model instances. You can pass an array of models to a collection constructor to get a collection of those models.

how to get model with backbone if i have it's URI?

I'm using django+tastypie+backbone.js with backbone-relational.
Let's say i have model(coffee script):
class Track extends Backbone.RelationalModel
And somehow i get the first object's URI:
api/track/1
Result in JSON have to be something like:
{
'title': 'Mytrack',
'length': '120'
}
How can i get full model JSON with all attributes using this URI?
You need to set the model's urlRoot (/api/track), then create a new model with the id you want (1), and call .fetch on the model. The fetch call will be asynchronous, so you need to wait for the success callback before you can access the full properties:
class Track extends Backbone.RelationalModel
urlRoot:"/api/track"
track = new Track id:1
track.fetch
success:(model) -> console.log model

How to automatically save on change in Backbone using localstorage?

Code:
class Session extends Backbone.Model
initialize: ->
#bind 'change', #save
console.log 'init'
class SessionList extends Backbone.Collection
model: Session
localStorage: new Store 'sessions'
sessions = new SessionList
a = new Session x: 'test'
sessions.add a
console.log a.get 'x'
a.set x: 'new'
console.log a.get 'x'
When loaded in a page with Backbone.localstorage, the console gives:
init
test
Uncaught TypeError: Cannot read property 'localStorage' of undefined
backbone-localstorage.js:70
Backbone.sync
_.extend.save
backbone-localstorage.js:70
Backbone.Events.trigger
backbone.js:304
_.extend.change
backbone.js:117
And when I comment out the #bind call, I get the expected:
init
test
new
I can also save manually successfully after a has been added to sessions with a call to a.save().
I guess the problem is that the Session constructor triggers the change event, and save() doesn't know what to do before a has been added to sessions? So I could instead do something like this:
class Session extends Backbone.Model
set: (fields, ops) ->
super fields, ops
if (this has been added to a Collection)
#save()
Is this the best way to do it? If yes, how do I fill in the if statement?
My suggestion would be to just call save instead of set. so replace this:
a.set x: 'new'
with
a.save x: 'new'
hope that works for you

How to avoid too many model classes

The number of models has grown quickly in my application. I'm wondering about your standard practices regarding backbone.js. Lets say you want to create a view that requires 2 other models. Do you create a new model class to contain the 2 models like this:
var m = new TheModel({
model1: new Model1,
model2: new Model2
});
var view = new TheView({model:m});
or do you just do something like:
var m = {
model1: new Model1,
model2: new Model2
};
var view = new TheView({model:m});
The second seems better because then I don't need the extra model class TheModel. But if I mix the two methods, then in my view I have to remember which style I'm using because if I want to get access to model1 or model2 then there are two different ways:
var m1 = this.model.get('model1');
or this way in the second scheme:
var m1 = this.model.model1;
Which is better in your opinion?? How do you organize all the models and views?
Thanks!
Unless there is a reason to link your models, I would not create a new model that aggregates other models. The second option is better because you are not linking them.
I prefer to separate them even further:
var view = new TheView({purchases: purchasesModel, user: userModel });
Then, inside the view, instead of referencing this.model, you reference this.purchases and this.user specifically.
You see, the model property on the views is really just a convention. There is nothing special about the model property in the view except that the model property will get copied automatically in the constructor. Other than that, there is no reference to the model in Backbone.View.
Of course, this means that you need to do something with it:
var TheView = Backbone.View.extend({
initialize: function(options) {
this.purchases = options.purchases;
this.user = options.user;
}
});
This way, you are being explicit about the multiple models that you require. I like this better than verison #2 because you are not as explicit about the requirements of the View.
You should use Collections in this case. Here you can read more about Collections: http://backbonetutorials.com/what-is-a-collection/

Resources