Search code examples
layoutbackbone.jsrequirejsmarionetteregion

Show Backbone Collection element in a Marionette region


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>

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).