daGrevis
daGrevis

Reputation: 21333

Is Backbone.js suitable for getting HTML from server?

As far as I can tell, Backbone.js view represents DOM element. I take it from existing DOM or create it on the fly in el attribute.

In my case, I want to take it from server with AJAX request because I'm using Django templates and don't want to rewrite everything to JavaScript templates.

So I define el function that performs AJAX request.

el: function() {
    model.fetch().success(function(response) {
        return response.template
    })
}

Of course, it does NOT work because AJAX request is executed asynchronous.

This means that I don't have el attribute and events does NOT work neither. Can I fix it?

Maybe the Backbone.js framework isn't the right tool for my needs? The reason I want to use that was to have some structure for the code.

P.S. I'm new to Backbone.js.

Upvotes: 1

Views: 906

Answers (2)

Kalpers
Kalpers

Reputation: 658

I came across a similar requirement. In my instance, I was running asp.net and wanted to pull my templates from user controls. The first thing I would recommend is looking into Marionette because it will save you from writing a lot of boiler plate code in Backbone. The next step is to override how your templates are loaded. In this case I created a function that uses Ajax to retrieve the HTML from the server. I found an example of this function where they were using it to pull down html pages so I did a little modification so I can make MVC type requests. I can't remember where I found the idea from; otherwise, I would give the link here.

function JackTemplateLoader(params) {
    if (typeof params === 'undefined') params = {};
    var TEMPLATE_DIR = params.dir || '';

    var file_cache = {};

    function get_filename(name) {
        if (name.indexOf('-') > -1) name = name.substring(0, name.indexOf('-'));
        return TEMPLATE_DIR + name;
    }

    this.get_template = function (name) {
        var template;
        var file = get_filename(name);
        var file_content;
        var result;
        if (!(file_content = file_cache[name])) {
            $.ajax({
                url: file,
                async: false,
                success: function (data) {
                    file_content = data; // wrap top-level templates for selection
                    file_cache[name] = file_content;
                }
            });
        }
        //return file_content.find('#' + name).html();
        return file_content;
    }

    this.clear_cache = function () {
        template_cache = {};
    };

}

The third step would be to override Marionette's method to load templates. I did this in the app.addInitializer method. Here I am initializing my template loader and setting it's directory to a route handler. So when I want to load a template, I just set the template: "templatename" in my view and Backbone will load the template from api/ApplicationScreens/templatename. I am also overriding my template compiling to use Handlebars because ASP.net is not impressed with the <%= %> syntax.

    app.JackTemplateLoader = new JackTemplateLoader({ dir: "/api/ApplicationScreens/", ext: '' });
    Backbone.Marionette.TemplateCache.prototype.loadTemplate = function (name) {
        if (name == undefined) {
            return "";
        } else {
            var template = app.JackTemplateLoader.get_template(name);
            return template;
        }
    };
    // compiling
    Backbone.Marionette.TemplateCache.prototype.compileTemplate = function (rawTemplate) {
        var compiled = Handlebars.compile(rawTemplate);
        return compiled;
    };
    // rendering
    Backbone.Marionette.Renderer.render = function (template, data) {
        var template = Marionette.TemplateCache.get(template);
        return template(data);
    }

Hopefully this helps. I've been working on a large dynamic website and it is coming along very nicely. I am constantly being surprised by the overall functionality and flow of using Marionette and Backbone.js.

Upvotes: 2

Marius Kjeldahl
Marius Kjeldahl

Reputation: 6824

Do your ajax request from another view, or directly after the page load using jquery directly, and after you've downloaded your template, THEN instantiate your backbone view class with the proper id/el or whatever (depending on where you stored your ajax fetched template). Depending on your use-case, this may or may not be a sensible approach.

Another, perhaps more typical approach, would be to set up your view with some placeholder element (saying "loading" or whatever), then fire off the ajax, and after the updated template has been retrieved, then update your view accordingly (replace the placeholder with the actual template you requested).

When/if you update your view with new/other DOM elements, you need to call the view's delegateEvents method to rebind your events to the new elements, see:

http://backbonejs.org/#View-delegateEvents

Upvotes: 2

Related Questions