Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Backbone Marionette, Composite View initializes twice

I'm using a composite view that has $.dialog called on it's $el.

The composite view is then listing items from a collection.

Now i've tried multiple ways to render the collection items: fetching from outside the composite view before and after attaching it to the view, fetching inside the view, preloading the collection from my server script, etc...

all seem to work but the same problem occurs..

as soon as the composite view see's this collection, it calls it's own initialize function again...

I fully understand that the render function will be called on a collection reset or add... but the initialize??? i have absolutely no idea why this is happening.

showCustomFieldSelect: function(e){

    log('triggered');

    e.preventDefault();

    var cl = new AustApp.Collections.CustomField;

    var select = new AustApp.Views.AvailableCustomFieldsList({
        el: "#available-custom-fields-popup",
        collection: cl
    });

    cl.fetch();


    cl.once("reset", function(){
        // this bind was
        // previously used for creating the view
        // or calling render functions directly
        // amongst numerous efforts to debug

    }, this);


},



MyApp.Views.AvailableCustomFieldsList = function(){

var AvailableCustomFieldsList = Backbone.Marionette.CompositeView.extend({

    template: "#available-contact-list-custom-field-list-js",

    tag: "div",

    itemView: AustApp.Views.AvailableCustomFieldsListItem,

    emptyView: AustApp.Views.EmptyAvailableCustomFieldsListItem,

    itemViewContainer: "ul",

    templateHelpers: viewHelpers,

    initialize: function(){
        log('init called'); // called twice?????
        this.render();
        this.$el.dialog({
            title: "Available Custom Fields",
            width: '600px',
            modal: true,
            dialogClass: "round",
        });
    },
    /* stuff */
});

return AvailableCustomFieldsList;
}();

Any help appreciated as I'm flummoxed

like image 705
Thomas Hudspith-Tatham Avatar asked Feb 22 '13 05:02

Thomas Hudspith-Tatham


5 Answers

For me, this was fixed (after many hours of banging my head on table), but making sure that the ItemView was declared before the CompositeView!!

Works:

MyItemView = Marionette.ItemView.extend({ /* STUFF */ })
MyCompView = Marionette.CompositeView.extend({ itemView: MyItemView })

Does not work (init called twice without any arguments):

MyCompView = Marionette.CompositeView.extend({ itemView: MyItemView })
MyItemView = Marionette.ItemView.extend({ /* STUFF */ })

It doesn't matter even if we get an instance of MyCompView after both are declared, the itemView must be declared before the compsite view is.

like image 171
simbolo Avatar answered Oct 13 '22 07:10

simbolo


so I've narrowed the problem down to when the item views are declared after the composite view which is also contained within another composite view.

changing the nested composite view into an item view fixed the problem, but then... changing the nested composite view into a collection view spat the error that the itemView for the collection wasn't available

and so moving the declaration of the nested view above the declaration of the collection view fixed it... Then changing it transpired that the nested composite views worked when the declarations were in the correct order.

I think this should be less misleading as a double initialization of the composite view is just plain confusing and should spit out an error regarding the undefined itemview instead if at all possible derick ^_^

Thanks

like image 29
Thomas Hudspith-Tatham Avatar answered Oct 13 '22 06:10

Thomas Hudspith-Tatham


Thanks for the above explanation.

I had the same problem. If there is no itemView defined with the Composite view, it calls its initialize function every time its collection changes.

I fixed this by using an empty view as item view.

(I was using my Composite view for some other purpose and did not required an item View with it.)

like image 29
KEINS Avatar answered Oct 13 '22 07:10

KEINS


For RequireJS Users and/or Users Compiling (Minizing) JavaScript

I want to add that when uglfying (minimizing) your JavaScript, the uglifying engine may declare things out of order (i.e. the CompositeView and ItemView may be declared in reverse order like @Thomas Hudspith-Tatham and @simbolo mentioned). The problem is more common when modularizing your Backbone.Marionette with requireJS, and optimizing (compiling) the code.

Unfortunately, I don't know of a guranteed fix, except recompiling the code, that has worked for me.

like image 29
seebiscuit Avatar answered Oct 13 '22 06:10

seebiscuit


I am sharing my experience. It might help some one.

I faced similar kind of problem. At Initial I thought event was fired twice but in real , it was listened twice which leads to abnormal application behavior.

My event was fired once from composite view (one trigger) but was listened twice (2 on) due to two instance of Contact controller.

I fixed by making sure that I have only one listener (one Controller instance) for a particular behavior (in my case open a edit dialog).

Note . I have multiple controller in my application and i am loading using require.

like image 23
Ravi Kumar27 Avatar answered Oct 13 '22 07:10

Ravi Kumar27