Search code examples
javascripttemplatesroutesdeferred

Display deferred data in template


Problem

I'm using this 20 line router to do my routing and templating.

What I am struggling with is using data in the template.

My templating engine is https://github.com/trix/nano.

What I have

I have a function that gets the users data (at the moment I am just trying to show a message):

adrLoadAddressBooks:function() {
    var deferred = new $.Deferred();
    var return_response = {};
    data = {
        country_code:config.country_code,
        language_code:config.language_code,
        source:config.source,
        usr_id:app.getCookie('usr_id'),
        login_token:app.getCookie('login_token')
    };
    app.api('adr/list',data,function(data) {
        var response = JSON.parse(data);
        return_response.msg = 'This user has address books.';
        if(!response.result) {
            return_response.msg = 'No address books found.'
        }
        deferred.resolve(return_response);
    },'post');
    return deferred.promise();
},

In my router, I get the data like so:

jsRouter.route('/adr','adr/index',function() {
    console.log('In route function');
    this.response = events.adrLoadAddressBooks().done(function(response) {
        console.log(response);
        return response;
    });
});

The console.log returns the following:

Object {msg: "This user has address books."} // correct

And in my template file I have the following:

<h4>Address Books</h4>
Message: {response.msg}
<a href="#/adr/create">Create Address Book</a>

Question

It currently only displays the template, no msg. If I change {response.msg} to just {response}, it displays [Object object] which is the response object so it is sending something.

How do I access the msg?


Solution

  • I fixed it by changing my router quite a bit. I have a loadPage() function that looks like this:

    loadPage:function(page,element,bindData) {
        $.get(page,function(data) {
            element.html(nano(data, bindData));
            app.setPageListeners();
        });
    },
    

    This was called at the end of my router() function (after the template has been found).

    router:function() {
        app.resetResponse();
        jsRouter.el = jsRouter.el || $('#view');
        var url = $.urlHash() || '/';
    
        if(typeof route == 'undefined' || typeof route == null) {
            route = jsRouter.routes['404'];
        }
        auth.isLoggedIn();
    
        if(jsRouter.el && route.controller) {
            jsRouter.loadPage(config.templates + route.template + '.html',jsRouter.el,new route.controller);
        }
    },
    

    Firstly, what I did was changed my actual route() function like so:

    route:function(path,template,callback) {
        jsRouter.routes[path] = {template: template, callback: callback };
    },
    

    So now I can pass a callback by setting up my route like this:

    jsRouter.route('/adr','adr/index',events.adrLoadAddressBooks);
    

    I then changed the end of my router to this:

     if(jsRouter.el) {
        if(route.callback) {
            jsRouter.loadData(config.templates + route.template + '.html',jsRouter.el,route.callback);
        } else {
            jsRouter.loadPage(config.templates + route.template + '.html',jsRouter.el,"");
        }
    }
    

    And then created a loadData function that waits for a deferred object before continuing, like so:

    loadData:function(page,element,callback) {
        if(typeof callback !== 'undefined') {
            if (typeof callback === "function") {
                callback().done(function(data) {
                    jsRouter.loadPage(page,element,data);
                });
            } else {
                alert("Could not call " + endpoint);
            }
        } else {
            jsRouter.loadPage(page,element,this);
        }
    },
    

    My callback, in this case, looks like this:

    adrLoadAddressBooks:function() {
        var deferred = new $.Deferred();
        //do stuff
    
        app.api('adr/list',data,function(data) {
            var response = JSON.parse(data);
            return_response.msg = 'Below is a list of all your address books.';
    
            if(!response.result) {
                return_response.msg = 'This user has no address books.';
                deferred.resolve(return_response);
            }
    
            //build response
    
            deferred.resolve(return_response);
        },'post');
    
        return deferred.promise();
    },
    

    And it works quite well. :) Obviously, if there's stuff that I can improve, add a comment

    EDIT 1

    Added extra step after route function.

    EDIT 2

    Full router available on Pastebin