So I have some objects extended from Backbone.js:
var MyModel = Backbone.Model.extend({});
var modelInstance = new MyModel();
var MyModelView = Backbone.View.extend({});
And I'm trying to figure out how to bind my Model to its corresponding View. How does one handle data-binding in Backbone?
You pass your model instance into the view when creating it.
var modelView = new MyModelView({model: modelInstance})
From the docs:
When creating a new View, the options you pass — after being merged into any default
options already present on the view — are attached to the view as this.options
for future reference. There are several special options that, if passed, will be
attached directly to the view: model, collection, el, id, className, tagName and attributes.
Related
I am currently trying to put a backbone model inside an already existing model. I was wondering if this is even possible.
var rf = this.collection.create(attrs, options);
Model.set(table, rf);
Thanks
What you trying to do is "Nested Models & Collections". Backbone already has preferable approach. The common idea consist in storing of nested model directly in the instance of another model instead attributes.
So, you could create child model first and then pass it to parent model through options like the following:
var rf = this.collection.create(attrs, options);
var Model = Backbone.Model.extend({
initialize: function(attributes, options) {
_.isObject(options) || (options = {});
if (options.child) {
this.child = new options.child;
}
}
});
var model = new Model({}, {child: rf});
If you want to get a fully supported tree-like Backbone models you could try to use one of the following plugins.
Hope this helps!
I have a base model, that is creating a view with several div's. It is not actually a form; but it is acting as a form. I have variables being set with defaults as well. Here's my model right now:
var BaseModel = require('base-m');
var SomeModel = BaseModel.extend({
defaults: function() {
return {
FirstName : null,
LastName : null,
Age : null,
State : null
};
}
update: function() {
return {
FirstName : $('[name="FirstName]').val()
};
console.log(FirstName);
}
});
I am trying to update the model with the particular value of whatever is entered. Do I need to use an event? I am doing this because I want to retrieve the updated variable for output purposes.
Also; (if it's different), lets say it's a drop down menu like states..? Would I update it similar to a text field like first name?
Thanks
It appears your model is accessing the DOM. Usually, your view would deal with the DOM, extracting information then updating the model.
So for example, create a view with a constructor that:
Creates your input elements and put them in an attribute called $el; then
Adds $el to the DOM; then
Binds event listeners to $el.
These event listeners can update model attributes via a reference to the model, e.g. this.model in the view's context.
The view can also watch the model for changes and update itself accordingly.
For example:
var SomeView = Backbone.View.extend({
// Store HTML of DOM node in template. Easy to change in future.
template: [
'<div class="blah">',
'<input type="text" class="hello" />',
'</div>'
].join(''),
initialize: function() {
// Create DOM node, add to DOM
this.$el = $(_.template(this.template)());
$("body").append(this.$el);
this.hello = this.$el.find('.hello');
// Update model when view changes
this.hello.on('keydown', this.updateModel);
// Update view when model changes
this.model.on('change', this.updateView);
},
updateModel: function(evt) {
this.model.set('hello', this.hello.val());
},
updateView: function() {
this.hello.val(this.model.get('hello'));
}
});
The code that creates your model could also create this view and pass the model reference to the view constructor, e.g.
var myModel = new SomeModel();
var myView = new SomeView({model: myModel});
Of course, all of the specifics will vary according to your situation.
If you would like to use an existing DOM node as $el, remove the first two lines of code that create and append $el. Then instantiate your view like:
var existingJqNode = $('#existing'); // find existing DOM node, wrap in jQuery object
var myView = new SomeView({
model: myModel,
$el: existingJqNode
});
Above all, think about how best to set this up. Does using an already existing DOM element as $el create an advantage? If you want to create more of these views in the future, what code is responsible for creating/adding the $els before each view is instantiated?
Hope that helps.
Case 1: Passing model as in options
var View1 = Backbone.View.extend({
initiliaze:function(){
}
});
Case 2 : Passing model as a param and setting it using this
var View2 = Backbone.View.extend({
initiliaze:function(model){
this.model = model
}
});
var view1 = new View1({model:someModel})
var view2 = new View2(someModel)
It's the same thing, except that in the first case you have less code in your view declaration because Backbone handle setting the model in the view for you (this.model = model).
In general Backbone can handle some parameters for you, you can take a look at the documentation to have more informations about it.
Here I am passing a model to a Backbone view.
view = new View ({model:{item:4,name:"Ipad"}});
When I console.log that model from within the View. I get:
Object {item: 4, title: "Ipad"}
This is not a backbone model therefore I don't have methods
like toJSON. I realize that if I define a Backbone model and
passed it in everything works fine.
view = new GenreView ({model:new Model({title: 4, title: "Ipad"})});
This logs
r {cid: "c2", attributes: Object, _changing: false, _previousAttributes: Object, changed: Object…}
Why is it that first approach doesn't work and how can I fix it?
Its simply that the special 'model' option expects a Backbone.Model not a javascript object.
So you are correct when you create a new Backbone.Model to pass into the view.
There is nothing to fix as far as I can tell.
You need to use a Backbone.Model instead of a regular JavaScript object {}
var Item = Backbone.Model.extend({
// ...
});
Instantiate the Item model
var myItem = new Item();
Now use your item in the view
var myView = new View({model: myItem});
This answer assumes that View is setup as something like
var View = Backbone.View.extends({
// ...
});
You could cast the object to a Backbone Model in your view's initialize method:
var View = Backbone.View.extend({
initialize: function(options){
if (_.isPlainObject(this.model)) {
this.model = new Backbone.Model(this.model);
}
}
});
This way the view will be able to operate on it's model regardless of whether you passed it an instance of a Backbone.Model or a plain object. You can see an example of it working here: http://jsbin.com/igecEgE/1/edit?js,console
I define a backbone view
Views.BaseView = Backbone.View.extend({
viewState : new Backbone.Model(),
initialize: function(){
this.listenTo(this.viewState, "change:stateType", this.onAlertType)
}
}
I have got GlobalView that extends BaseView, and that permits me to display and manage my ItemViews.
The ItemView extends as well the BaseView.
My problem is that if i change the viewState.stateType at the level of an ItemView :
MyItemView.viewState.set('stateType', 1)
the GlobalView is notify first about the change of the viewState property of the ItemView.
My GlobalView does not get any particular 'listenTo', the only 'listenTo' that I define is the one at the BaseView level.
Why the globalView is notified about the change on a viewState object define on ItemView ?
Does any one see what I am doing wrong ? Is that a known bug ?
When you define a property on a Backbone object (for example View) using .extend, the property is attached to the object's prototype. This means that the same property value is shared by all instances of that object.
This makes perfect sense on methods, because you don't want to create a new function instance for every method of each instance of your object. It's also relatively harmless on immutable value type properties, because the original value is not modified, and when you reassign the property with another value, a new property is created on the instance, and that hides the prototype property without modifying it:
var SomeView = BaseView.extend({
foo:'foo'
});
var view1 = new SomeView();
var view2 = new SomeView();
view1.foo = 'bar';
console.log(view1.foo, view2.foo); // -> bar, foo
The problem arises when you set a property to a mutable object, such as an Object, Array, or similar. When you change that object without reassigning the property, this changes that property value on all instances.
In your case the viewState properties of all views are pointing to the same model instance, so:
var view1 = new SomeViewThatExtendsBaseView();
view1.viewState.set('stateType', 1);
var view2 = new SomeOtherViewThatAlsoExtendsBaseView();
console.log(view2.viewState.get('stateType')); // -> 1
To declare instance properties using Backbone, you should create them in the initialize method:
Views.BaseView = Backbone.View.extend({
initialize: function() {
this.viewState = new Backbone.Model();
this.listenTo(this.viewState, "change:stateType", this.onAlertType)
}
}