Question

I have a Backbone application running and working properly with requirejs. Now, I'm trying to make a migration to Marionette in order to have the code better organized.

I just want to show a model from a collection in a region, with two buttons in another region. I want to go to the next or previous model from that collection. And change its view on the model region.

But I don't know how to iterate over the collection and send its model to the view.

jsfiddle with some simplified code with this situation.

html:

<div class="player"></div>

<script id="layout-template" type="text/template">
    <div class="modelView"></div>
    <div class="controls"></div>
</script>
<script id="model-region" type="text/template">
    <%=name%>
</script>
<script id="control-region" type="text/template">
    <button id="prev">Prev</button>
    <button id="next">Next</button>
</script>
Was it helpful?

Solution

If I understand your question, you are trying to coordinate events between two views on the same layout. In this case I would recommend setting up a Controller.

Then you can register view triggers for on your controls view:

ControlsView = Backbone.Marionette.ItemView.extend({
  // ...

  triggers: {
    "click #previous": "control:previous",
    "click #next": "control:next"
  }
});

An then in your controller you would instantiate your views and setup a handler for the controlView triggers to update the modelView.

var Router = Marionette.AppRouter.extend({
  appRoutes: {
      "/": "start",
      "/:index" : "showModel"
  },
});

var Controller = Marionette.Controller.extend({

  initialize: function(){
    var self = this;
    this.controlsView = new ControlsView();
    this.modelView = new MainView();
    this.myCollection = new MyCollection();
    this.myIndex = 0;
    this.myCollection.fetch().then(function(){
      self.myIndex = 0;
    });
    this._registerTriggers();
  },
  start: function(){
    this.controlLayout.show(this.controlView);
    this.showModel();
  },
  showModel: function(index){
    index = index || this.index;
    this.modelView.model = myCollection.at(this.index);
    this.modelLayout.show(this.modelView);
  },
  showNext: function(){
    var max = this.myCollection.models.length;
    this.index = max ? 1 : this.index + 1;
    this.showModel();
  },
  showPrevious: function(){
    var max = this.myCollection.models.length;
    this.index = 0 ? max : this.index - 1;
    this.showModel();
  },
  _registerTriggers: function(){
    this.controlsView.on("control:next", this.showNext());
    this.controlsView.on("control:previous", this.showPrevious());
  }
}

var controller = new Controller();
var router = new Router({
  controller: Mod.controller
});
controller.start();

Using this approach allows you to decouple your views and collection. This will make your code reusable (using the controls view in a different context as an example).

OTHER TIPS

You are looking for CollectionView or CompositeView.

The CollectionView will loop through all of the models in the specified collection, render each of them using a specified itemView, then append the results of the item view's el to the collection view's el.

A CompositeView extends from CollectionView to be used as a composite view for scenarios where it should represent both a branch and leaf in a tree structure, or for scenarios where a collection needs to be rendered within a wrapper template.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top