Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle async code in a backbone marionette initializer

I'm trying to put together backbone application using the marionette plugin, and am having some trouble getting initializers to work the way I expected them to. I have the following code:

var MyApp = new Backbone.Marionette.Application();

MyApp.addRegions({
    region1 : '#div1',
    region2 : '#div2'
});

MyApp.Resources = { };

MyApp.bind('initialize:before', function (options) {
    // display a modal dialog for app initialization
    options.initMessageId = noty({
        text : 'Initializing MyApp (this should only take a second or two)',
        layout : 'center',
        speed : 1,
        timeout : false,
        modal : true,
        closeOnSelfClick : false
    });
});

MyApp.addInitializer(function (options) {
    $.ajax({
        url: options.apiUrl + '/my-app-api-module',
        type: 'GET',
        contentType: 'application/json; charset=utf-8',
        success: function (results) {
            MyApp.Resources.urls = results;
            console.log(MyApp.Resources.urls); // <- THIS returns an object
        }
    });
});

MyApp.bind('initialize:after', function (options) {
    // initialization is done...close the modal dialog
    if (options.initMessageId) {
        $.noty.close(options.initMessageId);
    }

    if (Backbone.history) {
        Backbone.history.start();
    }

    console.log(MyApp.Resources.urls); // <- THIS returns 'undefined' BEFORE the console.log in the initializer above
});

Note in the code above that I have two console.log calls, one in the initializer, and one in the initialize:after handler. Both log the same object property. As you can see, what I'm experiencing is that the console.log call in the initialize:after handler is getting called before the one in the success handler of the initializer. I realize that this is because the initializer has an async call in it...what I need to know is, how can I make sure that all of the async code in my initializer(s) is complete before doing anything else in the application? Is there a good pattern for this? I've not found anything in the docs indicating how to handle this correctly.

Thanks.

like image 689
Bob Yexley Avatar asked Jul 16 '12 16:07

Bob Yexley


1 Answers

how can I make sure that all of the async code in my initializer(s) is complete before doing anything else in the application?

Don't use the initialize:after event. Instead, trigger your own event from the success call, and then bind your app start up code from that one.

MyApp.addInitializer(function (options) {
    $.ajax({
        url: options.apiUrl + '/my-app-api-module',
        type: 'GET',
        contentType: 'application/json; charset=utf-8',
        success: function (results) {
            MyApp.Resources.urls = results;

            // trigger custom event here
            MyApp.vent.trigger("some:event:to:say:it:is:done")

        }
    });
});

// bind to your event here, instead of initialize:after
MyApp.vent.bind('some:event:to:say:it:is:done', function (options) {

    // initialization is done...close the modal dialog
    if (options.initMessageId) {
        $.noty.close(options.initMessageId);
    }

    if (Backbone.history) {
        Backbone.history.start();
    }

    console.log(MyApp.Resources.urls);
});

This way you are triggering an event after your async stuff has finished, meaning the code in the handler will not run until after the initial async call has returned and things are set up.

like image 122
Derick Bailey Avatar answered Sep 29 '22 18:09

Derick Bailey