Update backbone model with new json - backbone.js

Right now, I'm passing json to model like this:
model m = new app.SomeModel(json);
and then using it, which seems fine.
However, now whenever my json changes, I want to pass the new json to the model, without creating a new instance of the model, something like:
m.updateJson(json);
EDIT: Right now I'm doing something like:
m.set(json)
But can we also do something like:
m.set("json_key",json)
So that later on I'll be able to do:
m.get("json_key")
to get the entire json ?

Just use model.set, it will trigger "change" events, and update dependent objects
setmodel.set(attributes, [options]) Set a hash of attributes (one or
many) on the model. If any of the attributes change the model's state,
a "change" event will be triggered on the model. Change events for
specific attributes are also triggered, and you can bind to those as
well, for example: change:title, and change:content. You may also pass
individual keys and values.
note.set({title: "March 20", content: "In his eyes she eclipses..."});
book.set("title", "A Scandal in Bohemia");
And If you need to trigger "sync" event, after you have updated a model issue
model.trigger("sync")

Related

Binding to property of model attribute in Backbone.js

Disclaimer: I'm new to Backbone.js (coming from AngularJS), so I may have an inaccurate mental model of how this is supposed to work.
I have an object, characterNodes, which I'm making an attribute on my model. characterNodes looks something like this:
var characterNodes = {
character_1: {
stories: [// list of Stories]
},
character_2: {
stories: [// list of Stories]
}
...
}
My Backbone Model looks something like this:
var StoryGraph = joint.dia.Graph.extend({
initialize: function() {
// Call parent constructor
StoryGraph.__super__.initialize.apply(this, []);
this.set('characterNodes', characterNodes);
this.on('change:characterNodes', function() {
alert('test');
});
}
});
Each Story has a property "isUnlocked" which is changed elsewhere in the application. I want to fire an event (ie. that is, the alert 'test' should pop up) whenever this property is changed. With the code as it is above, the event never seems to fire.
I can't get a clear understanding from the Backbone docs whether this is supposed to work - does on('change:characterNodes') fire whenever any property (or sub-property, or sub-sub-property, etc) of characterNodes changes? Or only when the pointer to the object changes, that is, when it's replaced with another object? Or am I doing something else wrong? Thanks!
Backbone doesn't do any magic, basically, the change event is fired only if you set the "characterNodes" to a new object. If you're changing a nested property of that object, Backbone doesn't know it happened. You have three options: a) Change the whole object (e.g. by creating a copy), b) fire the change event manually (m.trigger("change:characterNodes")) whenever you change a nested property, c) Do not use nested objects for this. Have "character1_Stories" as a top level property.
Options c) is preferable. Try to keep properties in your models flat. Option a) is also fine but it has the disadvantage of having to copy the object. Option b) is not recommended. This is because Backbone keeps track of the previous value of the model properties (m.previous("characterNodes")). If you change a nested property, the previous value will have the same reference to the same object as the new value, therefore, it won't reflect its previous state.
Try to call a function instead define the function, and pass the third argument to keep the context call.
Something like this:
this.on('change:characterNodes', this.AlertSomething, this);
Hope it helps.

backbone model with an array/object property: infinite 'change' event triggered after sync()?

My backbone.js model has an array property. I bound the change event to save().
After sync() (triggered by save(), my app server returns an identical JSON, but backbone thinks the array has been changed (due to a different reference to the array I guess?), and trigger changes again. Then an infinite loop occurs.
save() -> sync() -> triggered `change` -> save()...
What shall I do?
Idea: I can bind the change event to a function that checks if the changed attributes are of type object/array, and do a deep comparison and call save only if the array/object really changed. If true then save()?
Thanks!
Try the Edge version of Backbone (master branch) this behavior changed after 0.9.9 - see https://github.com/documentcloud/backbone/pull/2004
Backbone has a special option on many methods to prevent just this sort of issue: silent:true. If you pass that option to your save method, the resulting sync won't trigger a change event.
So, if you want to set your change event handler to save silently, something like:
changeHandler: function() {
this.save({silent:true});
}
should do the trick.

In backbone "why the model created", what is the use of it? - below is my code

I took a small code from backbone home site, and consoled the function, in this example, sidebar.on('change:color'), takes the function. but it requires two parameter, one is abiously we need that is 'color', and we defining the element inside the function, still why we giving another parameter as 'model' here, what that parameter does?
if i remove that parameter send only the color, the function doesn't work at all... any one help me to understand this?
sample function here:
var Sidebar = Backbone.Model.extend({
promptColor : function(){
var cssColor = prompt('Please enter a css color');
this.set({color:cssColor});
}
});
window.sidebar = new Sidebar;
sidebar.on('change:color',function(model,color){ // what model parameter do here?
console.log(model);
$('#sidebar').css({
background:color
})
})
sidebar.set({color:'green'});
sidebar.promptColor();
when i console the model i got this:
d
_callbacks: Object
_changing: false
_escapedAttributes: Object
_pending: Object
_previousAttributes: Object
_silent: Object
attributes: Object
changed: Object
cid: "c1"
__proto__: x
It is possible that you want to know which model was affected.
Consider a case where you are listening to an event on a collection instead. Which model's color value was modified? The model parameter tells you this.
Also, consider a case where the same handler is listening to "change:color" on multiple models. Again, you might want to know which model sent the event.
Just like in other event-driven environments, the "sender" is always passed along with the event data. model, in this case, is the sender.
Backbone is a Javascript MVC framework. (Unlike standard MVC, Backbone doesn't have controllers, instead it has collections).
The model you are receiving is a standard model from the MVC paradigm. Model's are the underlying data structures that hold the data that the user is working with.
When you do
sidebar.on('change:color', function(model, color) {
// some code here
});
you are attaching an event handler to the sidebar model. Specifically, you are saying that when the color attribute on this model changes, call the function. Since this event can and will trigger at a later point in time, Backbone passes the event handler function two arguments: the first is the model on which the event fired, and the second is the attribute that changed.
The arguments are passed in a specific order, that is model is the first argument, and the changed attribute is the second. Thus if you omit the model argument from your event handler function, the passed in model gets assigned to color, and color doesn't get assigned to any argument.
Recommended reading:
More about MVC and models
More about backbone models

Backbone.js event system (model and collection)

In Backbone.js (0.9.2) I have the following:
One collection and one method that gets called when something changes
this.collection.on("change", this.methodOne, this);
When I change a value of one model of this collection ...
model.set("value1", "abc");
... the change event from the model BUBBLES UP to the collection and so "methodOne" is called.
When I look into the source code of Backbone.js, "collection", method "add", a private
method "_prepareModel" is called that makes the model - collection reference:
model.collection = this;
But from there on I do not understand how and in which methods this bubble up mechanism
is functioning?
Has anybody got information for me about that?
Thanks alot in advance!
Wolfgang
Take a look at Backbone.Collection _onModelEvent method. In the docs:
Internal method called every time a model in the set fires an event. Sets need to update their indexes when models change ids. All other events simply proxy through. "add" and "remove" events that originate in other collections are ignored.

Backbone-Relational firing add event before server responds

I'm using Backbone-Relational in a project at the moment, and it's not behaving the way it seems like it should.
Let's say Model A has a HasMany relationship with Model B. Model A listens for an "add:model_b" event to render a necessary view for Model B whenever an instance is added to the Model A relationship. In order to render the view template properly though, we need some data from the server. From reading the backbone docs, it seems to me the logical way to do this would be as follows:
modelA.get("model_b").create(newModelData, {wait: true});
As Backbone-Relational implements relations as Backbone Collections, I just call the collection.create method to instantiate my new Model B, and pass {wait: true} to the options in order to delay the "add" event til the server responds.
However, this seems to have no effect: the "add" event is firing instantly, and I'm therefore getting an error when trying to render a view that needs data that is not yet part of the model. Does anyone know why {wait: true} is doing nothing in this instance, and how can I get the desired behavior out of Backbone-Relational?

Resources