slobodan.blazeski
slobodan.blazeski

Reputation: 1040

Right way for wiring backbone views

I have a two views:
   1 LeftView (maximized when RightView is minimized & vice versa)
   2 RightView (containing)
      - collection of 
         - RightItemView (rendering RightItemModel)

When RightView is maximized and the user clicks a RightItemView, I want to maximize LeftView and display something according to the data from the clicked RightItemView.

What's the proper way to wire them?

Upvotes: 2

Views: 402

Answers (3)

AlexandruSerban
AlexandruSerban

Reputation: 312

The solution given by @Ganeshji inspired me to make a live example

I've created 2 views for this.

var RightView = Backbone.View.extend({
  el: $('.right_view'),

  template: _.template('<p>Right View</p>'),

  renderTemplate: function () {
      this.$el.html('');
      this.$el.append(this.template());  
      this.$link = this.$el.append('<a href="#" title="some data" id="left_view_max">Item to view</a>').children('#left_view_max'); 
  },

  events: {
      'click #left_view_max'    :   'maxLeftView'
  },

  maxLeftView: function () {
    //triggering the event for the leftView
    lView.trigger('displayDataInLeftView', this.$link.attr('title'));
  },

  initialize: function (options) {  
      this.renderTemplate();
  }
});

var LeftView = Backbone.View.extend({
  el: $('.left_view'),

  template: _.template('<p>Left View</p>'),

  renderTemplate: function () {
      this.$el.html('');
      this.$el.append(this.template());
  },

  displayDataInLeftView: function (data) {
    this.$el.append('<p>' + data + '</p>');
  },

  initialize: function (options) {
    //set the trigger callback
    this.on('displayDataInLeftView', this.displayDataInLeftView, this);
    this.renderTemplate(); 
  }
});

 var lView = new LeftView();
 var rView = new RightView();

Hope this helps.

Upvotes: 1

Ganeshji Marwaha
Ganeshji Marwaha

Reputation: 477

The solution @jordanj77 mentioned is definitely one of the correct ways to achieve your requirement. Just out of curiosity, I thought of another way to achieve the same effect. Instead of using a separate EventDispatcher to communicate between the two views, why shouldn't we use the underlying model as our EventDispatcher? Let's try to think in those lines.

To start with, add a new boolean attribute to the RightItem model called current and default it to false. Whenever, the user selects the RightItemView, set the model's current attribute to true. This will trigger a change:current event on the model.

var RightItem = Backbone.Model.extend({
  defaults: {
    current: false,
  }
});

var RightItemView = Backbone.View.extend({
  events: {
    'click li': 'changeCurrent'
  }

  changeCurrent: function() {
    this.model.set('current', true);
  }
});

On the other side, the LeftView will be handed a Backbone.Collection of RightItem models during creation time. You would anyways have this instance to supply the RightView isn't it? In its initialize method, the LeftView will listen for change:current event. When the event occurs, LeftView will change the current attribute of the model it is currently displaying to false and start displaying the new model that triggered this event.

var LeftView = Backbone.View.extend({
  initialize: function() {
    this.collection.on('change:current', this.render, this);
  },

  render: function(model) {
    // Avoid events triggered when resetting model to false
    if(model.get('current') === true) {

      // Reset the currently displayed model
      if (this.model) {
        this.model.set('current') = false;
      }

      // Set the currently selected model to the view
      this.model = model;

      // Display the view for the current model
    }
  }
});

var leftView = new LeftView({
  // Use the collection that you may have given the RightView anyways
  collection: rightItemCollection 
});

This way, we get to use the underlying model as the means of communication between the Left and Right Views instead of using an EventDispatcher to broker for us.

Upvotes: 2

jordanj77
jordanj77

Reputation: 243

I would recommend using the Backbone.Events module:

http://backbonejs.org/#Events

Basically, this line is all it takes to create your event dispatcher:

var dispatcher = _.clone(Backbone.Events);

Then all of your views can trigger/listen for events using the global dispatcher.

So, in RightItemView you would do something like this in the click event:

dispatcher.trigger('rightItemClick', data); // data is whatever you need the LeftView to know

Then, in LeftView's initialize function, you can listen for the event and call your relevant function:

dispatcher.on('rightItemClick', this.maximizeAndDisplayData);

Assuming your LeftView would have a function like so:

maximizeAndDisplayData: function(data) {
    // do whatever you need to here
    // data is what you passed with the event
}

Upvotes: 2

Related Questions