How to access a composite view from an item view instance in Backbone Marionette
Asked Answered
C

3

29

The basic situation is this:

I have a Composite View and an Item View. I construct the Composite view passing it a model and a collection. The model data is used to populate the template for the Composite view. The collection data is used to populate the Item View for the Composite View.

What I want to do is this: in a template helper for the Item view I want to access the model data for the Composite View. I've got as far as accessing the view instance of the Item View. I thought that might give me a handle on the Composite View, from where I could get to its model, but it doesn't.

Is there a way I can do this - access the composite view instance from one of its item view instances?

Thanks

--Justin Wyllie

Cassaundra answered 10/7, 2013 at 13:53 Comment(0)
S
33

If you want to access data from the parent CompositeView you can do a number of different things.

  1. Either pass that data directly to the ItemView through the itemViewOptions helper function on the CompositeView. Note: This option has changed to childViewOptions in Marionette 2.

  2. Invoke a method directly on all of the children view from the CompositeView and pass whatever you want into that method.

  3. Trigger an event on or listened for by the ItemView.

None of these options are directly accessing the parent view from the child but should do what you want. Below is code for how to use each of these approaches to pass the CompositeView's model to the children view.

// Pass model into ItemView on init
var MyItemView = Backbone.Marionette.ItemView.extend({
  initialize : function (options) {
    this.parentsModel = options.parentsModel;
  }
});
var MyCompView = Backbone.Marionette.CompositeView.extend({
  itemViewOptions : function () { return { parentsModel: this.model }; }
  itemView : MyItemView
});


// Invoke function on ItemView, passing data in
var MyItemView = Backbone.Marionette.ItemView.extend({
  doSomethingWithParent : function (parentModel) {
    // do cool thing with parentModel
  }
});
var MyCompView = Backbone.Marionette.CompositeView.extend({
  itemView : MyItemView,
  onRender : function () {
    this.children.call("doSomethingWithParent", this.model);
  }
});


// Trigger event that ItemView knows about
var MyItemView = Backbone.Marionette.ItemView.extend({
  initialize : function () {
    this.listenTo(this, "special:event", function (parentModel) {
      // Do cool things
    });
  }
});
var MyCompView = Backbone.Marionette.CompositeView.extend({
  itemView : MyItemView,
  onRender : function () {
    this.children.each(_.bind(function (childView) {
      childView.trigger("special:event", this.model);
     }, this));
  }
});
Simferopol answered 10/7, 2013 at 18:47 Comment(5)
Thanks. You clearly understood exactly the point of my question - how to get the parent model into each instance of the child. All 3 options are useful.Cassaundra
This was a great explanation. Thank you!Nations
Note that as of Marionette 2, itemViewOptions has been renamed to childViewOptions (along with all other references to itemView within CollectionView/CompositeView)Annabel
Good point pimlottc. Thanks! Updated answer to include that as a note.Simferopol
@AndrewHubbs You made my day. Thanks for the answer +1 for you.Cad
C
1

I didn't answer the question. But changing the approach works. Instead of trying to access the 'parent' Composite View from the Item View I access the Item View from the Composite View:

https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.collectionview.md#onbeforeitemadded-callback

I can modify the model of the current item view (based on a value in the model of the Composite View).

Cassaundra answered 10/7, 2013 at 14:22 Comment(0)
N
1

Thought I'd share how Andrew Hubbs suggestion helped me. I was trying to display a parent model property inline with my item template. I used Marionette's templateHelpers property to do this in combination with one of Andrew's suggestions.

I tried to keep the example brief:

Example Composite template - myView Template:

<h1>Page {{name}}</h1>
<h6>Children</h6>
<ul></ul>

Example item template - myItemTemplate:

{{name}} is child of: {{getParentName}}

Views:

App.module( 'App.View', function( View ){

    View.MyItemView = Marionette.ItemView.extend({

        initialize: function( options ) {
            this.parentModel = options.parentModel;
        },

        template: myItemTemplate,

        tagName: 'li',

        templateHelpers: function() {

            var view = this;

            return {
                // Called by item template, returns parent model 'name' property.
                getParentName: function() {
                    return view.parentModel.get('name');
                }

            };
        }

    });

    View.MyView = Marionette.CompositeView.extend({

        template: myViewTemplate,

        itemView: View.MyItemView,

        itemViewContainer: 'ul',

        itemViewOptions: function() {

            return { parentModel: this.model };

        }

    });

});

An example of how this would be implemented:

// example of how implementation
// parent model has an attribute called 'children', which is a collection of models
var children = parent.get('children');

var view = new App.View.MyView( { model: parent, collection: children } );

App.mainRegion.show( view );
Nations answered 31/1, 2014 at 21:28 Comment(1)
Great example. Link to where this is mentioned in docs: github.com/marionettejs/backbone.marionette/blob/master/docs/…Brain

© 2022 - 2024 — McMap. All rights reserved.