8
votes

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

5
Can you build a JSFiddle or JSBin that shows the problem in action? I can't see anything wrong with the code off-hand, and it would be easier to see what's happening with running code. Thanks.Derick Bailey
Are you sure you aren't just creating two AvailableCustomFieldsList views? Is showCustomFieldSelect being called twice, perhaps? If you put a breakpoint in the initialize function, can you tell from the call stack why it is happening?Brian Genisio
no, showCustomFieldSelect is definitely only being called once, otherwise the log that says "triggered" would be being output twice, but as stated in my OP the only double call is from the initializeThomas Hudspith-Tatham

5 Answers

18
votes

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.

7
votes

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

2
votes

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

2
votes

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.

1
votes

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.