I'm new to backbone.js and I've a question regarding model definitions. In various tutorials and introductions I've seen those three approaches in defining a model:
Tour = Backbone.Model.extend({
idAttribute: 'id',
urlRoot: '/api/tour',
});
return Tour;
});
And the other next one:
**var** Tour = Backbone.Model.extend({
idAttribute: 'id',
urlRoot: '/api/tour',
});
return Tour;
});
I've also seen this one:
Tour = Backbone.Model.extend({
idAttribute: 'id',
urlRoot: '/api/tour',
});
return **new Tour()**;
});
I've read that the first one is in "the global namespace" which had in fact no effect for me in programming. So where is the difference between those three (especially first and second one) and when shall which be used?
1- In the first approach you are creating a global variable named Tour so wherever you are Tour will point to your model class.
2- In the second one you are creating a local variable pointing to your model class and returning it, so whenever you want want to use your model you have to instantiate the returned variable and that's it.
3- In the third approach you are creating your model class, instantiating it and returning the instance, so all your program will share the same instance !!
The correct approach is the second one, because in the first the use of global vars in javascript is discouraged and the the third approach is not working.
Related
I had the following setup now in three different projects, so I thought maybe it's worth asking here. There's a chance I'm not the only person wondering about this.
So there it comes:
I have a list of objects
The list items have a special function like draggable or onClick-Events
My question: How do I build this scenario with Backbone?
I guess I create a model and a view for my list objects. I use a collection for keeping together my objects.
Now I wonder: Do I instantiate the object view in the model constructor and instantiate the models in the collection constructor? Or is there a better way to achieve what I want?
Neither; use a mediator to instantiate the views and inject them with their model/collection.
Marionette.js has a nice implementation for this sort of mediating object, called Controller - I suggest you check it out.
Further more, you don't have to explicitly instantiate the collection models - just declare their type in the collection's prototype, e.g.:
var MyModel = Backbone.Model.extend({
// do some shit
});
var MyCollection = Backbone.Collection.extend({
model: MyModel // pass the type for the collection to instantiate
});
Taking our mediator/controller approach further, this is how it could be done (with Marionette.js):
var MyController = Marionette.Controller.extend({
initialize: function () {
this.myCollection = new MyCollection();
this.myCollectionView = new MyCollectionView({
collection: this.myCollection
});
}
});
This, of course, is just a skeleton code, meant to roughly demonstrate the MVC approach, but it's a good starting point.
I'm trying to minimize server calls by avoiding any requests I can.
Let's say, for the sake of a example, I have a collection of Matchboxes which belong to Users and have Tags assigned, and then also have a collection of Tags and a collection of Users as part of other pages. Getting matchboxes retrieves the user and tag info, so that I can instantiate all required models with one request, accessing the Tags and Users pages retrieves similar collections (only they deal only with their respective models).
My problem: if matchboxes is one page, and tags and users are two other pages, what's a good way to make sure only one model is ever instantiated for any given entity, ie. if I go into users or tags and edit an entry associated with a matchbox the matchbox entry should have the same entry assigned allowing it to listen and react to the updates with out requiring sending requests when going back to the matchbox page in the example.
I've looked over Backbone.relational but it doesn't seem to do what I need, and would rather not wall myself into a framework. So solutions involving patterns are preferable.
Ended up using http://pathable.github.io/supermodel/ which uses the pattern of overwriting the model attribute on collections with a custom function which calls a special Model.create that itself returns an existing (updated with the new values if necessary) instance of said model. The Model.create call has to be used everywhere else in code for unique models.
So essentially every model has a all() method which is a collection of all instances by id. Whenever a model is added it checks it against the collection and returns an existing object if it exists; the data used to instantiate the duplicate is used to update the existing object ensuring data is not stale (which is a nice bonus to the uniqueness I wanted).
The cleanest method seems to be to just wrap the model function into a function that returns it for clearer use; then for every collection that needs to have unique models wrap said model in the function. I came up with this at the moment:
app.single = function (modelPrototype) {
return function (attrs, options) {
return modelPrototype.create(attrs, options);
};
};
(app there is just a scope global, tied to a particular namespace)
So in collections instead of,
model: app.Model
I would then use
model: app.single(app.Model),
Whenever I update a entry in one part of the application the change will trickle down to every other collection/model since if it's the same instance from the user's perspective it's the same instance in code too.
That's about all I could tell from reading the pattern though the code and documentation. Which is sufficient for my own uses.
I suspect this solution would still have some issues if you're caching renders but I haven't found a use for that (prefer to re-render whenever I can to avoid dealing with various artifacts) so it's all good for me.
Unfortunately the codebase seems to be partially abandoned, so while it works with Backbone 1.0.0 (as far as unique models go), I may need to re-create/fork the pattern in future projects.
I think you should think twice about nesting your models and collections in this way, especially if it's primarily for the purpose of easing the bootstrapping of your app. Instead, try to use id's for inter-referencing between models as much as possible. This design problem you have is most likely only the first of many to come if you structure your model/collection tree in a certain way now, only to find it too inflexible later.
That being said, If all you need is for models referencing other models/collections to be able to refer to the same model/collection instance, then simply instantiating them during bootstrap and passing them in to their respective parent models would be sufficient. You could either load some bootstrap data in one request, or preferably inline that data in the HTML:
<script>
var bs_data = {
users : [
...
],
tags : [
...
],
matchboxes : [
...
]
};
</script>
And then instantiate the corresponding models or collections using the bootstap data.
var matchboxes = new Matchboxes();
matchboxes.set(bs_data.matchboxes);
var users = new Users({matchboxes:matchboxes});
users.set(bs_data.users);
The bootstrap data would come from the same backend so your models and collections would already be in sync without having to fetch anything.
As for design patterns; passing dependencies as constructor arguments is actually the dependency injection pattern, albeit more automated solutions to do so exist.
To make sure only one model is ever instantiated, and it is shared among the other elements that use it, being able to listen and update when any of the elements make a change to it, you can use a Singleton pattern. You can read more about it here
If you use Requirejs you can get same effect if you always return the model instantiated. For example:
// the shared model
define([
'jquery',
'underscore',
'backbone'
], function ($, _, Backbone) {
'use strict';
var Model = Backbone.Model.extend({
// ...
});
// return instantiated, so we'll get the same object back whenever we use this model (singleton)
return new Model();
});
// a view using the model
define([
'jquery',
'underscore',
'backbone',
'model'
], function ($, _, Backbone, modelInstance) {
'use strict';
var View = Backbone.View.extend({
initialize: function () {
// listen to what other elements do
this.listenTo(modelInstance, 'eventFromOtherElement', this.doSomething);
// when this element does something, other elements should be listening to that event
modelInstance.trigger('thisViewEvent');
},
doSomething: function () {
// ...
}
});
return View;
});
I have been reading and following several Backbone.js tutorials and when it comes to defaults for the model people seem to do it one of two ways.
First Way - Defaults are an object
The first way is that defaults are declared as an object, for example;
my_model = Backbone.Model.extend({
defaults: {
title: 'Default Title'
}
});
This makes most sense to me, I immediately know that the defaults is an object and it works fine.
Second Way - Defaults are a function
The second way I have seen this is is that defaults are declared as a function, for example;
my_model = Backbone.Model.extend({
defaults: function() {
return {
title: 'Default Title'
}
}
});
This function obviously ends up returning an object, and to me makes little sense (unless you wanted to pass something into the function eventually.
My Question
My question is, is there a benefit to using one over the other assuming that you will not be passing any parameters using the function way. My feeling is that there may be a minuscule overhead from having the anonymous function be called but would love a more informed opinion.
Remember that in JavaScript, objects are passed by reference, so if you include an object as a default value, it will be shared among all instances. Defaults containing objects passed by reference should be defined using a function if you do not wish to share objects between all instances
https://github.com/documentcloud/backbone/issues/1145
Pretty much sums it up. The function method is only recommended when you have object attributes.
I think there are not any performance difference between the 2 techniques you have described. The way the defaults is resolved (= function called or just the object returned) is decided by this line in underscore.js:
return _.isFunction(value) ? value.call(object) : value;
As for the benefits. The regular object offers a static way of declaring the model defaults. You declare them when extending and thats it, they won't change. The function on the other hand provides you with the ability to change the model defaults of the fly without re-creating the whole class, by modifying the object the function is supposed to return.
Another reason to use a function instead of an object is if one of your defaults depends on a method in the model.
e.g.
defaults: function() {
return {
title: this.getTitle()
}
I have a store "Contacts". In my application i'm using this in 2 grids and 1 combo box. In Each of these components have varying screen space so i need to define pageSize. What is the best practise for this scenario. Is it better do create 3 different stores. ( I'm using MVC ) . If so, are there naming conventions.
Edit
Currently i load the stores in the onLaunch method in my controller
var partsStore = this.getPartsStore();
partsStore.pageSize = 15;
partsStore.load({
scope: this
});
and reference this store in my view
Ext.define('Mis.view.JobPartList', {
extend: 'Ext.grid.Panel',
alias: 'widget.jobpartlist',
store: 'Parts',
Yes, you should create multiple store instances. Not sure what you mean about naming conventions, the store name should stay the same whether you have 1 or multiple instances.
Based on the code you've posted above, it's not going to work, because by adding it to the class definition you're telling it to explicitly share the store.
Ext.define('Foo', {
// ...
initComponent: function(){
this.store = new MyStoreType();
// ...
this.callParent();
}
});
I have trouble keeping track of the properties of a Model instance. For example I have declarations such as:
MyModel = Backbone.Model.extend({});
Then in my views, I'm often doing something like:
var someVal = this.model.get('someProperty');
I was beginning the task of moving a View's strings into constants by encapsulating them in an object and passing it as a second parameter to a View's constructor, for example:
SchemaOptionsView = Backbone.View.extend(
{ /* Body of View here as usual */},
{
TEMPLATE: '#View-Template',
INPUT_REQUIRED:'required'
});
When I got to thinking, I could solve two problems by doing this with my Models:
MyModel = Backbone.Model.extend(
{ /* Body of Model here as usual */},
{
PROPERTY_1 = 'p1',
PROPERTY_2 = 'p2'
});
I could then use the constant to retrieve the property value:
var someVal = this.model.get(MyModel.PROPERTY_1);
This would allow me to clearly see the properties a Model instance contains, and also moves a string value into a constant in an appropriate place.
I have not seen this recommended or in any examples. Have I missed something? What do people think about this idea?
This is solving a non problem. Your models should have well defined attributes - we use the defaults hash to enumerate all the available attributes of our models. Not only does this provide a catalog of the attributes that a model possesses but it also provides a way to override a non-validated input.