Backbone Marionette, Composite View initializes twice
Asked Answered
H

5

9

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

Heel answered 22/2, 2013 at 5:30 Comment(3)
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.Brillatsavarin
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?Subchaser
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 initializeHeel
H
7

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

Heel answered 25/2, 2013 at 0:28 Comment(3)
I'd look into require.js. At the top of each module you define it's dependencies and then require.js takes care of the proper load order for you.War
thanks, I've been using require.js for the past 4 months.. this problem was with two views in the same file however so not necessary.Heel
With require.js I've gotten in the habit of only defining one view, model, collection, etc. per file. I end up with lots of files but I concat/optimize them all together for production so it doesn't matter.War
P
18

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.

Philippians answered 9/7, 2013 at 9:4 Comment(1)
Thanks a lot dude. I wasted my whole day on this issue. +1000 points :)Wane
H
7

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

Heel answered 25/2, 2013 at 0:28 Comment(3)
I'd look into require.js. At the top of each module you define it's dependencies and then require.js takes care of the proper load order for you.War
thanks, I've been using require.js for the past 4 months.. this problem was with two views in the same file however so not necessary.Heel
With require.js I've gotten in the habit of only defining one view, model, collection, etc. per file. I end up with lots of files but I concat/optimize them all together for production so it doesn't matter.War
S
2

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

Shona answered 28/5, 2013 at 7:34 Comment(0)
A
2

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.

Azral answered 12/6, 2014 at 14:29 Comment(1)
Yikes, I haven't noted this as an issue yet in my RequireJS Marionette, noted however.Night
G
1

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.

Gripper answered 12/1, 2014 at 7:16 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.