Last Updated: February 25, 2016
·
478
· crusoexia

A simple Backbone muck-up subview implementation

Backbone is a really elegant, light weight and flexible lib, and because of it's flexibility, it leaves a great gap to you to make it works as a "framework". Here is an example of how to write a Backbone muck-up subview which can let you place your subview in the html instead of combine them in the JavaScript.

Dependencies

To implement the subview in the muck-up, we need below libs to work with Backbone together:

Handlebars

Underscorejs

Requirejs

Jquery

Usage

Let's see how it works first. Put below snippet in your html and leave the rest work to The Handlebars

{{render model id="myRenderer" class="myClass" renderer="path.of.renderer" otherAttributes}}

or

{{render renderer="path/of/renderer" otherAttributes}}

Implement

// A subview holder of the current stage. Can be used to
// retrieve the views, or tear down when leave the stage.
var stage = [];

(function() {

    Handlebars.registerHelper('render', function(context, options) {
        var attributeHash = (options && options.hash) || context.hash, 
            tag = attributeHash.tag || "div",
            viewModel = options ? context : null,
            token = _.uniqueId();

        if (attributeHash.renderer)
            // Make sure the render action is always asynchronously.
            setTimeout(function() { 
                render(token, tag, viewModel, attributeHash); 
            }, 0); 
        else
            throw new Error(
                "Backbone sub view renderer requires a 'renderer' attribute.");

        // Return the html place holder.
        return new Handlebars.SafeString(
            [ "<", tag," renderer-id='", token, "'></", tag,">" ].join(""));
    });

    function render(token, tag, model, hash) {
        require([ hash.renderer ], function(SubView) {
            var $placeHolder = $([ tag, "[renderer-id=", token, "]" ].join("")),
                subView = null;

            if (SubView.prototype instanceof Backbone.View) {
                subView = new Renderer({
                    token: token,
                    model: model,
                    attributes: _.omit(hash, "tag")
                });

                stage.push({
                    token: token,
                    view: subView
                });

                $placeHolder.replaceWith(renderer.$el);
            } else {
                throw new Error(
                    "The subview renderer must inherit from Backbone.View.");
            }
        });
    }
})();