Marionette js itemview not defined: then on browser refresh it is defined and all works well - race condition?

StackOverflow https://stackoverflow.com/questions/19580767

Domanda

Yeah it's just the initial browser load or two after a cache clear. Subsequent refreshes clear the problem up.

I'm thinking the item views just aren't fully constructed in time to be used in the collection views on the first load. But then they are on a refresh? Don't know.

There must be something about the code sequence or loading or the load time itself. Not sure. I'm loading via require.js.

Have two collections - users and messages. Each renders in its own collection view. Each works, just not the first time or two the browser loads.

The first time you load after clearing browser cache the console reports, for instance:

"Uncaught ReferenceError: MessageItemView is not defined"

A simple browser refresh clears it up. Same goes for the user collection. It's collection view says it doesn't know anything about its item view. But a simple browser refresh and all is well.

My views (item and collection) are in separate files. Is that the problem? For instance, here is my message collection view in its own file:

messagelistview.js

    var MessageListView = Marionette.CollectionView.extend({
        itemView: MessageItemView,
        el: $("#messages")
    });

And the message item view is in a separate file:

messageview.js

    var MessageItemView = Marionette.ItemView.extend({
        tagName: "div",    
        template: Handlebars.compile(
                '<div>{{fromUserName}}:</div>' +
              '<div>{{message}}</div>' +
        )
    });

Then in my main module file, which references each of those files, the collection view is constructed and displayed:

main.js

    //Define a model
    MessageModel = Backbone.Model.extend();

    //Make an instance of MessageItemView - code in separate file, messagelistview.js
    MessageView = new MessageItemView();


    //Define a message collection 
    var MessageCollection = Backbone.Collection.extend({
        model: MessageModel    
    });

    //Make an instance of MessageCollection
    var collMessages = new MessageCollection(); 


    //Make an instance of a MessageListView -  code in separate file, messagelistview.js
    var messageListView = new MessageListView({
        collection: collMessages
    });

    App.messageListRegion.show(messageListView);

Do I just have things sequenced wrong? I'm thinking it's some kind of race condition only because over 3G to an iPad the item views are always undefined. They never seem to get constructed in time. PC on a hard wired connection does see success after a browser refresh or two. It's either the load times or the difference in browsers maybe? Chrome IE and Firefox on a PC all seem to exhibit the success on refresh behavior. Safari on iPad fails always.

PER COMMENT BELOW, HERE IS MY REQIRE BLOCK: in file application.js

    require.config({
        paths: {
            jquery: '../../jquery-1.10.1.min',
            'jqueryui': '../../jquery-ui-1.10.3.min',
            'jqueryuilayout': '../../jquery.layout.min-1.30.79',
            underscore: '../../underscore',
            backbone: '../../backbone',
            marionette: '../../backbone.marionette',
            handlebars: '../../handlebars',
            "signalr": "../../jquery.signalR-1.1.3",
            "signalr.hubs": "/xyvidpro/signalr/hubs?",        
            "debug": '../../debug',
            "themeswitchertool": '../../themeswitchertool'
        },

        shim: {
            'jqueryui': {
                deps: ['jquery']
            },

            'jqueryuilayout': {
                deps: ['jquery', 'jqueryui']
            },

            underscore: {
                exports: '_'
            },

            backbone: {
                deps: ["underscore", "jquery"],
                exports: "Backbone"
            },

            marionette: {
                deps: ["backbone"],
                exports: "Marionette"
            },        

            "signalr": {
                deps: ["jquery"],
                exports: "SignalR"
            },

            "signalr.hubs": {
                deps: ["signalr"],
                exports: "SignalRHubs"
            },

            "debug": {
                deps: ["jquery"]
            },

            "themeswitchertool": {
                deps: ["jquery"]
            }
        }
    });


    require(["marionette", "jqueryui", "jqueryuilayout", "handlebars", "signalr.hubs", "debug", "themeswitchertool"], function (Marionette) {
        window.App = new Marionette.Application();

        //...more code

    })

Finally, inside the module that uses creates the collection views in question, the list of external file dependencies is as follows:

    var dependencies = [
        "modules/chat/views/userview",
        "modules/chat/views/userlistview",
        "modules/chat/views/messageview",
        "modules/chat/views/messagelistview"
    ];

Clearly the itemViews are listed before collectionViews. This seems correct to me. Not sure what accounts for the collectionViews needing itemViews before they are defined. And why is all ok after a browser refresh?

È stato utile?

Soluzione

The sequence in which you load files is most likely wrong: you need to load the item view before the collection view.

Try putting all of your code in the same file in the proper order, and see if it works.

The free preview to my book on Marionette can also guide you to displaying a collection view.

Edit based on calirification:

The dependencies listed for the module are NOT loaded linearly. That is precisely what RequireJS was designed to avoid. Instead the way to get the files loaded properly (i.e. in the correct order), is by defining a "chain" of dependencies that RequireJS will compute and load.

What you need to do is define (e.g.) your userlistview to depend on userview. In this way, they will get loaded in the proper order by RequireJS. You can see an example of a RequireJS app here (from by book on RequireJS and Marionette). Take a look at how each module definition decalre which modules it depends on (and that RequireJS therefore needs to load before). Once again, listing the modules sequentially within a dependecy array does NOT make them get loaded in that sequence, you really need to use the dependency chain mechanism.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top