渲染视图中的骨干子视图

时间:2012-08-11 03:45:14

标签: backbone.js subviews

我的问题是使用Backbone子视图渲染视图的最佳方法。

虽然围绕这个主题有很多博客,但我还没有找到任何可以应用于这个用例的实用想法。

背景故事

在页面加载时,骨干提取并呈现远程模型和远程页面模板。

页面模板由3个字段集组成,每个字段集包含大量只读数据和图像,并带有[编辑]按钮。

+-----------------------+ +-----------------------+
| ID: ViewA             | | ID: ViewB             |
|                       | |                       |
|                       | |                       |
|                  EDIT | |                  EDIT |
+-----------------------+ +-----------------------+
+-----------------------+
| ID: ViewC             |
|                       |
|                       |
|                  EDIT |
+-----------------------+

当用户点击[edit]时,我想创建一个子视图,获取部分(下划线模板),应用现有模型,最后替换fieldset的innerHTML。

这将使字段集中的先前只读内容可由用户编辑和保存。一旦用户保存(或取消),它应该回到服务器,并重新呈现只读视图。

为了论证,让我们说模板托管在/templates/edit/<fieldsetid>.html

以下是现有代码:

模型和收藏

// Model
window.Page = Backbone.Model.extend();

// Collection
window.PageCollection = Backbone.Collection.extend({
    model: Page, 
    url: '/page/view.json'
});

视图

window.PageView = Backbone.View.extend({

    initialize:function () {
        this.model.bind("reset", this.render, this);
    },

    events:{
        'click fieldset a[role=edit-fieldset]' : 'edit'
    },

    edit: function(e){
        e.preventDefault();
        // @TODO Do some subview awesomeness here?
    },

    render:function (eventName) {
        _.each(this.model.models, function (data) {
            $(this.el).append(this.template({data: data.attributes}));
        }, this);
        return this;
    }

});

路由器

var AppRouter = Backbone.Router.extend({
    routes:{
        "page/view":"pageView"
    },
    pageView:function (action) {
        this.page = new PageCollection();
        this.pageView = new PageView({model:this.page});
        this.page.fetch();
        $('#content').html(this.pageView.render().el);
    }
});

模板加载器

// Borrowed from:
// http://coenraets.org/blog/2012/01/backbone-js-lessons-learned-and-improved-sample-app/
// Should probably move to RequireJS and AMDs

utils.loadTemplate(['PageView'], function() {
    var app = new AppRouter();
    Backbone.history.start();
});  

所以考虑到这一点,你有什么想法?我是在正确的轨道上吗?我应该看看另一种模式吗?

提前致谢。

1 个答案:

答案 0 :(得分:0)

我通常接近这些情况的方式如下(使用上面现有的'loadTemplate',Page和PageCollection架构):

// Model
window.Page = Backbone.Model.extend();

// Collection
window.PageCollection = Backbone.Collection.extend({
    model: Page, 
    url: '/page/view.json'
});

window.PageView = Backbone.View.extend({

    template: templates.pageViewTemplate,

    render: function() {
        var html = this.map(function(model) {
            // Important! We don't need to store a reference to the FieldSetViews.
            // Simply render them and by passing in the model, we can update the view
            // as needed when the model changes.
            // 
            // This is also good to reduce the potential for memory-leaks.
            return new FieldSetView({
                model: model
            }).render();
        });

        // Do one DOM update.
        this.$el.html(html);

        return this.$el;
    }
});

window.FieldSetView = Backbone.View.extend({

    events: {
        "click .edit": "_onEdit"
    },

    template: templates.fieldSetTemplate,

    render: function() {
        // Replace the top-level div created by backbone with that of your 
        // template (i.e fieldset). This gets around having to use 
        // the tagName property which should really be in your template.
        this.setElement(this.template.render(this.model.toJSON()));

        return this.$el;
    },

    _onEdit: function(e) {
        // Handle edit mode here by passing the model to another view
        // or by enhancing this view to handle both edit and view states.
    }

});