Search code examples
backbone.js

Two way data binding in backbone.js


I'm developing a jQuery Backbone.js web application.
As it is in Adobe Flex, I have implemented 2 way data binding in my app for input elements/widgets. So, every input element/widget knows its corresponding model and model attribute name.
When the user hits tab or enter, the field value is automatically given to the model.

container.model.set(this.attrName, this.value, options); // command 1

In the other direction, when the model gets updated from the backend, the view of the input element/widget should automatically get updated:

container.model.bind("change:"+ this.attrName, this.updateView, this); // command 2

The problem is:
When the user hits enter and the model is automatically updated, also the "change:abc" is triggered and this.updateView is called, not only when a new model comes from the backend.

My solution until now was to pass an option "source: gui" when setting the model value when the user pressed enter (command 1), and to check for that in my updateView method. But I am not content with this solution anymore.

Does anybody have a better solution? Thanks alot in advance
Wolfgang

Update:
When the option silent: true is passed, the validate method of the model is not called, so that does not help. See Backbone.js source 0.9.2:

_validate: function(attrs, options) {
  if (options.silent || !this.validate) return true;

Solution

  • From Backbone.js site:

    A "change" event will be triggered, unless {silent: true} is passed as an option

    options.silent = true;
    container.model.set(this.attrName, this.value, options);
    

    Update: You added a new comment to your question, so I just complemented my answer to fix the new use case(validation flow) that you mentioned:

    var ExtendedModel = Backbone.Model.extend({
        uiChange : false,
        uiSet: function (attributes, options, optional) {
            this.uiChange = true;
            this.set(attributes, options, optional);
            this.uiChange = false;
        }
    });
    
    var MyModel = ExtendedModel.extend({
    });
    
    var model = new MyModel();
    model.on('change:name', function(){
      console.log('this.uiChange: ', this.uiChange);
    });
    
    //simulates the server side set
    model.set({name:'hello'});
    
    //simulates the ui side set you must use it to set from UI
    model.uiSet({name:'hello2'});