Pergunta

I am cleaning up a multi-page app of 65+ html pages and a central javascript library. My html pages have a ton of redundancies and the central js library has become spaghetti. I face limitations on consolidating pages because I am working within a larger framework that enforces a certain structure. I want to reduce the redundancies and clean up the code.

I discovered backbone, MVC patterns, microtemplating and requirejs, but they seem best for single page applications. Somehow I need to let the main module know what page is being loaded so it will put the right elements on the page. I am thinking of passing in the title of the html which will turn grab the correct collection of page elements and pass them into App.initialize as an object.

1) Can anyone validate this approach? If not are there alternate approaches recommended? How about extensions to backbone like marionette?

2) Can anyone recommend a means to get page specifics into the backbone framework?

Following backbone tutorials I built a successful test page with a main.js that calls an App.initialize method that calls a view.render method. My first thought is to read the html page title and use it to select a model for the specific page being loaded. I'd have to pass in an object with the specifics for each pages layout. Here's the view's render method so you can see what I am trying to do:

            render: function () {  // pass parameter to render function here?
            var data = new InputModel,
                pageTitle = data.pageTitle || data.defaults.pageTitle,
                compiled,
                template;

            var pageElements = [
                { container: '#page_title_container', template: '#input_title_template' },
                { container: '#behavior_controls_container', template: '#behavior_controls_template' },
                { container: '#occurred_date_time_container', template: '#date_time_template' }]

            for (var i = 0; i < pageElements.length; i++) {
                this.el = pageElements[i].container;
                compiled = _.template($(InputPageTemplates).filter(pageElements[i].template).html());
                template = compiled({ pageTitle: pageTitle });  
                //pass in object with values for the template and plug in here?
                $(this.el).html(template);
            }
        }

Your help will be greatly appreciated. I am having a lot of fun updating my circa 1999 JavaScript skills. There's a ton of cool things happening with the language.

Foi útil?

Solução

Using the document title to choose the loaded scripts sounds a tad kludge-y. If it works, though, go for it.

Another idea worth exploring might be to utilize Backbone.Router with pushState:true to setup the correct page. When you call Backbone.history.start() on startup, the router hits the route that matches your current url, i.e. the page you are on.

In the route callback you could do all the page-specific initialization.

You could move the template and container selection out of the view into the router, and set up view in the initialize() function (the view's constructor). Say, something like:

//view
var PageView = Backbone.View.extend({
    initialize: function(options) {
        this.model = options.model;
        this.el = options.el;
        this.title = options.title;
        this.template = _.template($(options.containerSelector));
    },

    render: function() { 
        window.document.title = title;
        var html = this.template(this.model.toJSON());
        this.$el.html(html);
    }
});

Handle the view selection at the router level:

//router
var PageRouter = Backbone.Router.extend({
    routes: {
        "some/url/:id": "somePage",
        "other/url":    "otherPage"
    },

    _createView: function(model, title, container, template) { 
        var view = new PageView({
            model:model,
            title:title
            el:container,
            templateSelector:template,
        });
        view.render();
    },

    somePage: function(id) { 

        var model = new SomeModel({id:id});
        this._createView(model, "Some page", "#somecontainer", "#sometemplate");
    },

    otherPage: function() {
        var model = new OtherModel();
        this._createView(model, "Other page", "#othercontainer", "#othertemplate");
    }
});

And kick off the application using Backbone.history.start()

//start app
$(function() {
    var router = new PageRouter();
    Backbone.history.start({pushState:true});
}

In this type of solution the view code doesn't need to know about other views' specific code, and if you need to create more specialized view classes for some pages, you don't need to modify original code.

At a glance this seems like a clean solution. There might of course be some issues when the router wants to start catching routes, and you want the browser to navigate off the page normally. If this causes serious issues, or leads to even bigger kludge than the title-based solution, the original solution might still be preferrable.

(Code examples untested)

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top