Backbone.js : initialize Model with dynamic name - backbone.js

In backbone.js I can initialize a model with
var model = new MyModel();
But I would like to initialize a model with a dynamic name - like "MyDynamicModel". How can I achieve this?

If your models are declared globally (on the window object), then you can use the square bracket notation:
var Model = window[modelName]; // Assuming modelName is the dynamic name of your model
var model = new Model();
Or, if your models are namespaced under something like App.Models:
var Model = App.Models[modelName];
var model = new Model();
As a last resort, you can use Javascript's eval function, but in general this should be avoided.
var Model = eval(modelName);
var model = new Model();

You can use a wrapper object to get somewhat similar outcome.
var wrapper = {
"myDynamicName": new MyModel(),
"myOtherModel": new MyModel()
}
Then you can call it like this:
wrapper["myDynamicName"].render();

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.

Using a literal object as a Backbone.Model

I need to send a literal object to a view. Is there any better alternative to the following code:
var model= (new (Backbone.Model)).set({'foo':1,'bar':3})
just simply
var model = new Backbone.Model({'foo':1,'bar':3})
Yes, if you're just passing in some variables that are not relevant to the view data, then you should not be passing in a model. I can think of two other, more performant, ways to get data into your view.
Passing in data on instantiation
Every view will take parameter passed into the View constructor and hand them off the the view initialize (Backbone does a bit more with passed in parameters, but they all end up in initialize). Let me show you a trivial example.
var MyView = Backbone.View.extend({
initialize: function(options) {
// All the parameter you pass into the view construct with will be
// in the initialize options
// Attach options to the view so you can access your options
// from all view properties (bound to the view)
this.options = options || {};
}
}
Now get your object literal into your view:
var aView = new MyView({'foo':1,'bar':3});
aView.options.foo; // 1
aView.options.bar; // 3
Making data available after instantiation
If you want to merge an object after instantiation, then simply use _.extend:
_.extend(aView, {'foo':1,'bar':3});
aView.foo; // 1
aView.bar; // 3

Using Collections in Backbone.js

The following would be the model of a simple backbone application. So consider i want to have more than one url calls, i am told i should be using collections(definition is a collection of models).
Model format :
var Books1 = Backbone.Model.extend({
urlRoot: '/books1'
});
var Books2 = Backbone.Model.extend({
urlRoot: '/books2'
});
Collection format :
var Books = Backbone.Collection.extend({
url: '/books'
});
My question is how can i like combine more than one model in a collection ?
To be more clear :
Consider i have currently 8-10 models in a single view(need to call 8+ server requests from a single view). I am succesfully doing this via models. But from my initial research i came to conclusion that i should be using collection which will be a collection of all the models used. So by passing the collection to view, i will be able to call out different models at different part of view as requried.
And how do i use it in a view?
To be more clear :
for a model now i use this.model.save() or newmodel.save() after declaring the model before the place where i need to have the request done.
Cheers
lots of properties is handled via http://underscorejs.org/#result so you can pass urlRoot as function
var Books = Backbone.Model.extend({
urlRoot: function(){
return condition ? '/books' : '/bum'
}
});
same in collection. But I don't think so, its a good idea to combine 2 or more models in one collection. Just make a new collection for another model, if its possible....
what about view?
you can pass collection to view instance like this:
var SomeView = Backbone.View.extend({
initialize: function(opt){
this.collection = new opt.collection
}
});
var someView = new SomeView({collection: Books})

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