How to handle async code in a backbone marionette initializer
Asked Answered
L

3

6

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.

Labialize answered 16/7, 2012 at 16:9 Comment(0)
U
7

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.

Unfriendly answered 16/7, 2012 at 16:55 Comment(3)
Well now seeing that answer in writing, it seems to obvious to me that I feel a little bit foolish that I wasn't able to figure it out myself. Thanks Derick.Labialize
nothing foolish about it. it isn't obvious if you don't know the answer :)Unfriendly
I was thinking this, and felt foolish for googling it. but the syntax you posted helped clarify my thoughts ;) Thanks Derick for responding and thanks OP for asking the question!Pylorectomy
F
0

I wrote an override to the start method using jQuery deffereds so you can specify an Async initializer like authentication. The start method then waits til all deferreds are resolved and then finishes the start.

I replace marionette callbacks with my new sync callbacks class so I can use the regular methods calls in the app. Take a look at my solution and see if that helps at all. https://github.com/AlexmReynolds/Marionette.Callbacks

Flaw answered 6/1, 2014 at 21:8 Comment(0)
T
0

This can be used to accomplish tasks before the rest of your application begins. Check the documentation.

// Create our Application
var app = new Mn.Application();

// Start history when our application is ready
app.on('start', function() {
  Backbone.history.start();
});

// Load some initial data, and then start our application
loadInitialData().then(app.start);
Tripetalous answered 3/7, 2015 at 18:42 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.