1
votes

I am trying to render an events section in my Marionette application. I've taken the approach o fusing a composite view containing my CollectionView.

I'm thinking that the CompositeView will render CollectionView and then the CollectionView will render my list of ItemViews (events).

Currently, the CompositeView renders the CollectionView, but no ItemViews are instantiated or rendering.

This is my first Marrionette application. I am using node for the dep. management. Gulp to build, browserify, and babel. I followed this project to get everything going so far: https://github.com/thejameskyle/marionette-wires

Your help is greatly appreciated!! Thank you!

CompositeView

import {
  CompositeView
} from 'backbone.marionette';
import {
  CollectionView
} from 'backbone.marionette';
import {
  Collection
} from 'backbone';
import template from './events-template.hbs';
import EventsService from '../services/events-service';
import EventsView from './events-view';
import EventModel from '../models/events-model';
import EventsCollection from '../collections/events-collection';
export default CompositeView.extend({
  template: template,
  className: 'col-md-3 calendar',
  childViewContainer: "ul",
  model:EventModel,



  regions: {
    events: '.events-list',
  },
  initialize: function(){
    let self = this;
    EventsService.find().then(collection => {
      self.collection = collection;
      console.log('Events CompositeView '+self.collection);
      self.childView = new EventsView({collection:self.collection});
    });
  },

  setup(options = {}) {
    this.container = options.container;
    console.log("setup");
  },

  modelsChanged() {
    console.log('Events ModelChanged' + this.model);
  }
});

Events-Template.hbs

<section class="panel">
  <div class="panel-body">
    <div class="monthly-stats pink">
      <div class="clearfix">
        <h4 class="pull-left">Calendar</h4>
        <!-- Nav tabs -->
        <div class="btn-group pull-right stat-tab">
          <a href="#line-chart" class="btn stat-btn active" data-toggle="tab">Week</a>
          <a href="#bar-chart" class="btn stat-btn" data-toggle="tab">Month</a>
        </div>
      </div>
    </div>
    <div class="events-list">

    </div>
  </div>
</section>

CollectionView

import {
  CollectionView
} from 'backbone.marionette';
import {
  Collection
} from 'backbone';
import EventView from './event-view';
export default CollectionView.extend({
  tagName: 'ul',
  childView: EventView,
  childViewContainer: '.events-list',

  getChildView: function(item) {
    console.log('ChildView' +item);
  },

  initialize: function() {
    console.log('EVENTs CollectionView '+this.collection);
    for(let val of this.collection.models) {
      console.log(val.attributes);
    }
  },
  onBeforeRender: function() {
    console.log('Before EVENT CollectionView '+this.collection);
  },
  collectionEvents: {
    all: 'render'
  },
  childEvents: {
    // This callback will be called whenever a child is rendered or emits a `render` event
    render: function() {
      console.log('A child view has been rendered.');
    }
  }
});

ItemView //All logging in the itemView is just to see if anything is being called. Which it is not.

import {
  ItemView
} from 'backbone.marionette';
import {
  Collection
} from 'backbone';
import template from './event-template.hbs';


export default ItemView.extend({
  template: template,
  tagName:'div',
  className: 'col-md-3',
  attributes() {

  },
    onShow: function() {
      console.log('Single EVENT');
    },
  initialize: function(o) {
    console.log('init itemView');
  },
  show() {
    console.log("ITEM");
  },
  modelEvents: {
    all: 'render'
  },
  onBeforeRender() {
    console.log("EVENZT VIEW");
  },
  render() {
    console.log("EVENZT VIEW");

  },
  modelsChanged() {
    console.log('Events ModelChanged' + this.model);

  }
});

Event-Template.hbs

 <div class="alert alert-info clearfix">
      <span class="alert-icon"><i class="fa fa-envelope-o"></i></span>
      <div class="notification-info">
        <ul class="clearfix notification-meta">
          <li class="pull-left notification-sender"><span><a href="#">{{eventName}}</a></span></li>
        </ul>
        <p>
          <span>{{program}}</span><span>
        </p>
      </div>
    </div>
2
CompositeView is an extension of CollectionView - you do not need both. Simply pass your collection into your CompositeView along with the necessary options such as childView and childViewOptions.J. Titus
Thank you!! Now, to wait to render the itemviews until the CollectionView collection is populated.user1026498

2 Answers

3
votes

Adding to the comment which @J. Titus made, you have asked how to wait till all the ItemViews of the CollectionView are rendered, you can use this:

var ItemView = Backbone.Marionette.ItemView.extend({
    onShow: function () {
        this.trigger('childOnShow');
    }
});

var View = Backbone.Marionette.CollectionView.extend({
    childView: ItemView,
    childEvents: {
        'childOnShow': 'onChildShowHandler'
    },
    onChildShowHandler: function () {
        this.count++;
        if (this.count === this.collection.length) {
            // call your function here
        }
    },
    onShow: function () {
        this.count = 0;
    }
});

Hope this would solve your concern.

0
votes

As @J. Titus already commented on, you could use either CompositeView or CollectionView.

I'd recommend using CollectionView since you only need a region for displaying the list model views.

The thing about your collection is that you never populate it in your code. When you create a new collection it's empty unless you specifically pass an array of models. So you need to call .fetch() or .reset() (I recommend the latter for first-time use and for getting a lot of models all at once).

Since in your collectionEvents you're capturing all the events and render it, the view should update itself when the models have been loaded.