andrewpthorp
andrewpthorp

Reputation: 5096

Backbone.js Model vs. View SET

If I am using Backbone, which (or both) of these is the "correct" way to set data?

// Logic in the Model
// Can call from anywhere that has access
SomeModel = Backbone.Model.extend({
  defaults: {
    visible: false
  },

  toggle: function(visible){
    visible = typeof visible !== "undefined" ? visible : !this.get("visible");
    this.set({visible: visible});
  }
});

OR

// Logic in the View
SomeView = Backbone.View.extend({
  events: {
    "click .toggle" : "toggleVisibility"
  },

  toggleVisibility: function(){
    this.model.set({visible: !this.model.get("visible")});
  }
});

Obviously either one of these work, but my question is how much of that logic should be pushed off to the model? If, for instance, I have a situation that updates two variables:

this.model.set({visible: false, foo: bar, something: else});

Would it make sense to create a function on the model like this:

someFunction: function(visible, foo, something){
  this.set({visible: visible, foo: foo, something: something});
}

That just seems like overkill to me, but the set({}) logic in the view feels dirty.

Thoughts?

Upvotes: 2

Views: 2727

Answers (4)

lubar
lubar

Reputation: 2639

Similar question, with a great answer, here: Should views set model data?

As with most previous commenters, the general answer seems to be: if you're changing display elements, set data in the View. If you're setting business logic, set data in the Model.

Upvotes: 0

clexmond
clexmond

Reputation: 1549

It seems that you're mixing view logic into your models which isn't really a great idea. I would imagine there is some data in your model that is relevant to whether the view that has it bound should be visible (something like deleted: true, etc.) but you should toggle visibility based on that attribute changing. I would envision something like:

SomeModel = Backbone.Model.extend();

SomeView = Backbone.View.extend({
  events: {
    "click .toggle" : "toggleDeleted"
  },

  initialize: function() {
      this.model.on('change:deleted', this.toggleVisibility);
  },

  toggleDeleted: function() {
    var deleted = this.model.get('deleted');
    this.model.set({deleted: !deleted});
  },

  toggleVisibility: function(){
    this.$el.toggle(); // jQuery function toggling visibility
  }
});

// Somewhere in your "controller" logic
var someModel = new SomeModel({deleted: false});
var someView = new SomeView({model: someModel, el: DOMelement});

That way all your view logic is in your view and not your model. The model is empty since backbone has no need to define a schema, but generally you'll add functionality there at some point.

Upvotes: 0

Dor
Dor

Reputation: 902

It might feel dirty because you're used to the differentiation between views and controllers. In Backbone.js, however, it does not exist - views are also controllers. When you understand that, the interactions with the models become a whole lot easier on the eyes...

In my opinion, the correct way to solve your problem is a combination of the methods you introduced. Leave SomeModel.toggle in place, and in your view do:

    toggleVisibility: function() { this.model.toggle(); }

Upvotes: 1

asawyer
asawyer

Reputation: 17808

I would have the toggle function a member of the model, and call it from your view(s), hiding the implementation details. Remember a model can be represented by more then one view at a time, so any common model logic should be centralized there.

Maybe something like:

// Logic in the Model
// Can call from anywhere that has access
SomeModel = Backbone.Model.extend({
  defaults: {
    visible: false
  },

  toggle: function(visible){
    visible = typeof visible !== "undefined" ? visible : !this.get("visible");
    this.set({visible: visible});
  }
});
OR

// Logic in the View
SomeView = Backbone.View.extend({
  initialize: function() {
      this.model.bind('change:visibility',this.changeVisibility);
  }
  events: {
    "click .toggle" : "toggleVisibility"
  },

  toggleVisibility: function(){
    this.model.toggle();
  }
  changeVisibility: function() { 
      ........
      /// seems like alot of extra work to get to this point
      /// but remember, all views for the model are will receive this
      /// event now, not just the one that received the UI click
      /// whether or not that's the behavior you want is up to you. 
      ........
  }
});

Upvotes: 1

Related Questions