Marti Markov
Marti Markov

Reputation: 766

Marionette CompositeView called on every element add from collection, which belongs to the CompositeView... Why?

The problem is that every single time I add a new object through the fetch function of a collection (MovieCollection) on each element add some sort of event triggers and it initialises a new MovieList object to which the collection was passed after it has fetched all the items.

Here is my app.js:

// Global App skeleton for backbone
var App = new Backbone.Marionette.Application();
_.extend(App, {
    Controller: {},
    View: {},
    Model: {},
    Page: {},
    Scrapers: {},
    Providers: {},
    Localization: {}
});

// set database
App.addRegions({ Window: ".main-window-region" });

App.addInitializer(function(options){
    var mainWindow = new App.View.MainWindow();
    try{
        App.Window.show(mainWindow);
    } catch(e) {
        console.error("Couldn't start app: ", e, e.stack);
    }
});

So basically I create the MainWindow View which looks like:

(function(App) {
    "use strict";

    var MainWindow = Backbone.Marionette.LayoutView.extend({
        template: "#main-window-tpl",

        id: 'main-window',

        regions: {
            Content: '#content',
        },

        initialize: function() {
            //Application events
            //App.vent.on('movies:list', _.bind(this.showMovies, this));
        },

        onShow: function() {
            this.showMovies();
            //App.vent.trigger('main:ready');
        },

        showMovies: function(e) {
            var browser = new App.View.MovieBrowser();
            this.Content.show(browser);
        }
    });

    App.View.MainWindow = MainWindow;
})(window.App);

Here is the MovieBrowser which should make the collection, fetch it and then on the show would pass it to the MovieList.

(function(App) {
    'use strict';

    var MovieBrowser = Backbone.Marionette.LayoutView.extend({
        template: '#movie-browser-tpl',
        className: 'movie-browser',
        regions: {
            MovieList: '.movie-list-region'
        },

        initialize: function() {
            console.log('Init MovieBrowser');
            this.movieCollection = new App.Model.MovieCollection([], {});
            this.movieCollection.fetch();
        },

        onShow: function() {
            var ml = new App.View.MovieList({
                collection: this.movieCollection
            });
            this.MovieList.show(ml);
        }
    });

    App.View.MovieBrowser = MovieBrowser;
})(window.App);

So in turns the MovieCollection is (with I guess a major problem being something with it):

(function(App) {
    "use strict";

    var MovieCollection = Backbone.Collection.extend({
        model: App.Model.Movie,

        initialize: function(models, options) {
            console.log('Init MovieCollection');
        },

        fetch: function() {
            this.add([{"imdb":"1598172","title":"Once Upon a Time in Brooklyn","year":2013,"MovieRating":"4.1","image":"http://zapp.trakt.us/images/posters_movies/217035-300.jpg","bigImage":"http://zapp.trakt.us/images/posters_movies/217035-300.jpg","torrents":{"1080p":{"url":"https://yts.re/download/start/739F9B2F114DB4B48D34DEE2787725FF0747F6F3.torrent","size":"1768399511","seed":"2712","peer":"1709"},"720p":{"url":"https://yts.re/download/start/E482DC66BA1117F3706FACD0292BD32F1CDFE5F5.torrent","size":"854590014","seed":"1553","peer":"828"}},"backdrop":"http://zapp.trakt.us/images/fanart_movies/217035-940.jpg","synopsis":"After being released from prison, Bobby goes back to the mob connected streets. When forced to make a life altering decision the truth is revealed that he was too blind to see.","genres":[],"certification":"R","runtime":116,"tagline":"","trailer":""}]);
        },
    });

    App.Model.MovieCollection = MovieCollection;
})(window.App);

And MovieList is:

(function(App) {
    "use strict";

    var SCROLL_MORE = 200;

    var ErrorView = Backbone.Marionette.ItemView.extend({
        template: '#movie-error-tpl',
        onBeforeRender: function() {
            this.model.set('error', this.error);
        }
    });

    var MovieList = Backbone.Marionette.CompositeView.extend({
        template: '#movie-list-tpl',
        tagName: 'ul',
        className: 'movie-list',
        itemView: App.View.MovieItem,
        itemViewContainer: '.movies',
        initialize: function() {
            console.log('Init MovieList')
            if (typeof this.collection !== 'undefined') {
                //this.listenTo(this.collection, 'loading', this.onLoading);
                //this.listenTo(this.collection, 'loaded', this.onLoaded);
                //this.collection.fetch();
            } else {
                console.trace()
            }
        },
    });

    App.View.MovieList = MovieList;
})(window.App);

This is the MovieItem:

(function(App) {
    "use strict";

    var MovieItem = Backbone.Marionette.ItemView.extend({
        template: '#movie-item-tpl',
        tagName: 'li',
        className: 'movie-item',
        ui: {
            coverImage: '.cover-image',
            cover: '.cover'
        }
    });

    App.View.MovieItem = MovieItem;
})(window.App);

With finally the Movie model being:

(function(App) {
    "use strict";

    var Movie = Backbone.Model.extend({
        idAttribute: 'imdb',
        initialize: function() {
        },
    });

    App.Model.Movie = Movie;
})(window.App);

So in order to run it I basically have to check if collection is undefined. To see if it would continue and it does but the application itself is not working properly as it creates several MovieList items adding several ul elements with the same id.

here is the html templates:

http://jsfiddle.net/tarazo8e/

and this is the order of inclusion of the JS files:

<!-- App Initialization -->
{{ HTML::script('js/App/app.js') }}

<!-- Backbone Views and Controllers -->
{{ HTML::script('js/App/views/main_window.js') }}

{{ HTML::script('js/App/views/movie_browser/movie_browser.js') }}
{{ HTML::script('js/App/views/movie_browser/movie_item.js') }}

<!-- Backbone Models -->
{{ HTML::script('js/App/models/movie.js') }}
{{ HTML::script('js/App/models/movie_collection.js') }}


{{ HTML::script('js/App/views/movie_browser/movie_list.js') }}

I tried moving movie_list.js at almost any position with no luck.

Any help would be so so so much appreciated as this is driving me crazy for the past 5 days.

Credits: The code has been taken from an old version of Popcorn-Time for only learning purposes.

Edit:

Live versions that shows the exact error:

http://googledrive.com/host/0Bxf4SpRPErmGQmdKNmoyaEVSbmc

Upvotes: 0

Views: 318

Answers (1)

knpsck
knpsck

Reputation: 833

Try to swap moview_browser.js and moview_item.js. ItemView should be defined first.

The default rendering mode for a CompositeView assumes a hierarchical, recursive structure. If you configure a composite view without specifying an childView, you'll get the same composite view class rendered for each child in the collection.

Upvotes: 1

Related Questions