Only client-side attributes in Backbone

I have a pretty general model and a set of this model (see below). I consider it as the basis for a number of submissions. In some of the views, selecting one of the models generates actions (via the "selected" attribute), and I need to be able to track the selection only on the client side.

However, there seems to be no clean way to do this in Backbone. Any attributes added / changed in the model on the client will be synchronized with the server. I can’t use {silent : yes}when changing this attribute, because I need to initiate changes in my views when the event changefires on this attribute. The only way I came up with is to overwrite the function saveonBackbone.Model

My question is: is there a way to have only client-side attributes that I am missing OR is my approach structurally corrupted in some other way that I just don't see?

    var CSEvent = Backbone.Model.extend({
        idAttribute: "_id",
        urlRoot : '/api/events',
        defaults: {
            title : "",
            type : "Native",
            repeatOrOneTime : "OneTime",
            selected : false
        }
    });    

    var CSEventCollection = Backbone.Collection.extend({
        model: CSEvent,
        url: '/api/events',
        getSelectedEvent : function() {
            return this.find(function(csevent) { return csevent.get('selected') === true; });
        },
        selectEvent : function(eventId) {
            this.deselectEvent();
            this.get(eventId).set({selected : true});
        },
        deselectEvent : function() {
            this.getSelectedEvent().set({selected : false});
        }
    });
+5
source share
3 answers

Try overriding the method Model.toJSON(), as you can see in the code of the base model, this method does not make it very complicated. Also, official documentation suggests overriding it in case of special needs.

Try something like this:

var CSEvent = Backbone.Model.extend({
  toJSON: function(){
    return _.clone( _.pick( this.attributes, "title", "type", "repeatOrOneTime" ) );
  }
});
+5
source

I do not recommend overriding Model.toJSON(), because perhaps you want to use the JSON representation in other parts of the code, for example, when transferring the Backbone model to a micro-template.

- Model:

   sync: function(method, model, options) {
        if (method == 'update' || method == 'create') {
            var newModel = this.clone();
            newModel.unset('ignoredAttribute', {silent: true);
            return Backbone.sync.call(newModel, method, newModel, options);
        } else {
            return Backbone.sync.call(this, method, this, options);
        }
    },

ignoredAttribute.

:

  var CSEvent = Backbone.Model.extend({
    idAttribute: "_id",
    urlRoot : '/api/events',
    defaults: {
        title : "",
        type : "Native",
        repeatOrOneTime : "OneTime",
        selected : false
    },
    sync: function(method, model, options) {
        if (method == 'update' || method == 'create') {
            var newModel = this.clone();
            newModel.unset('selected', {silent: true);
            return Backbone.sync.call(newModel, method, newModel, options);
        } else {
            return Backbone.sync.call(this, method, this, options);
        }
    }
});   

selected ( Backbone), trigger. :

  var CSEvent = Backbone.Model.extend({
    idAttribute: "_id",
    urlRoot : '/api/events',
    selected : false,
    defaults: {
        title : "",
        type : "Native",
        repeatOrOneTime : "OneTime"
    },
    select: function() {
         this.selected = true;
         this.trigger('selected'); // you can use another event name here, ie. change
    },
    deselect: function() {
         this.selected = false;
         this.trigger('deselected');
    }
});   
+1

, , toJSON().

- , .

Take the following example where we give the user the ability to change their password.

var UserModel = Backbone.Model.extend({

  defaults: {
    username: "",
    password: {
      old: "",
      new: "",
      confirm: ""
    }
  },

  validate: function(attrs) {
    if (attrs.password.new !== attrs.password.confirm) {
      return "Passwords must match";
    }
  },

  toRemoteJSON: function() {
    var payload = this.toJSON();
    delete payload.password.confirm;
    return payload;
  },

  sync: function(method, model, options) {
    if (method == 'update' || method == 'create') {
      var newModel = this.clone();
      newModel.clear({ silent: true });
      newModel.set(this.toRemoteJSON(), { silent: true });
      return Backbone.sync.call(newModel, method, newModel, options);
    } else {
      return Backbone.sync.call(this, method, this, options);
    }
  }

});

When model saved is, the method validate()is called before the method sync(), and therefore it checks for two new passwords. The method then syncpasses toRemoteJSON(), which removes the password confirmation field before sending it to the server.

The function toRemoteJSON()simply abstracts the part newModel.unset()in Diego's solution. But now this means that you can define overridden syncin the base object, and for objects that extend from this, you only need to define toRemoteJSON().

+1
source

All Articles