Backbone Marionette嵌套复合视图

时间:2013-04-26 11:32:41

标签: backbone.js marionette

所以我被卡住了。我得到了伟大的Backbone.Marionette来处理嵌套的孩子/父母关系和渲染(用裸骨干做这件事是一场噩梦),但现在我遇到了嵌套复合视图的问题,

我总是得到一个未找到指定的itemViewContainer:.tab-content 来自父复合视图 - CategoryCollectionView,虽然itemViewContainer在模板上可用,这里是我正在尝试做什么,我有一个我需要提供的餐馆菜单,所以我有几个类别,在每个类别中我有几个菜单项,所以我的最终HTML将是这样的:

    <div id="order-summary">Order Summary Goes here</div>
    <div id="categories-content">
         <ul class="nav nav-tabs" id="categories-tabs">
              <li><a href="#category-1">Appetizers</a></li>
         </ul>
         <div class="tab-content" >
               <div class="tab-pane" id="category-1">
                    <div class="category-title">...</div>
                    <div class="category-content">..the category items goes here.</div>
         </div>
     </div>

这是我到目前为止所做的:

首先是模板

模板骨架

<div id="order-summary"></div>
<div id="categories-content"></div>

模板菜单芯

<ul class="nav nav-tabs" id="categories-tabs"></ul>
<div class="tab-content" ></div>

模板类别

<div class="category-title">
    <h2><%=name%></h2>
    <%=desc%>
</div>
<div class="category-content">
    The menu items goes here
    <ul class="menu-items"></ul>
</div>

模板菜单项目

Item <%= name%>
<strong>Price is <%= price%></strong>
<input type="text" value="<%= quantity %>" />
<a href="javascript:void()" class="add">Add</a>

现在是剧本

var ItemModel = Backbone.Model.extend({
    defaults: {
        name: '',
        price: 0,
        quantity: 0
    }
});

var ItemView = Backbone.Marionette.ItemView.extend({
    template: '#template-menuitem',
    modelEvents: {
        "change": "update_quantity"
    },
    ui: {
        "quantity" : "input" 
    },
    events: {
        "click .add": "addtoBasket"
    },
    addtoBasket: function (e) {
        this.model.set({"quantity": this.ui.quantity.val() });
    },
    update_quantity: function () {
        //@todo should we do a re-render here instead or is it too costy
        this.ui.quantity.val(this.model.get("quantity"));
    }
});

var ItemCollection = Backbone.Collection.extend({
    model: ItemModel
});



var CategoryModel = Backbone.Model.extend({
    defaults: {
        name: ''
    }
});

var CategoryView = Backbone.Marionette.CompositeView.extend({

    template: '#template-category',

    itemViewContainer: ".menu-items",
    itemView: ItemView,

    className: "tab-pane",
    id: function(){
        return "category-" + this.model.get("id");
    },

    initialize: function () {

        this.collection = new ItemCollection();
        var that = this;
        _(this.model.get("menu_items")).each(function (menu_item) {
            that.collection.add(new ItemModel({
                id: menu_item.id,
                name: menu_item.name,
                price: menu_item.price,
                desc: menu_item.desc
            }));
        });


    }
});


var CategoryCollection = Backbone.Collection.extend({
    url: '/api/categories',
    model: CategoryModel
});

var CategoryCollectionView = Backbone.Marionette.CompositeView.extend({

    el_tabs: '#categories-tabs',

    template: '#template-menu-core',
    itemViewContainer: ".tab-content", // This is where I'm getting the error
    itemView: CategoryView,

    onItemAdded: function (itemView) {
        alert("halalouya");
        //this.$el.append("<li><a href=\"#cateogry-" + tab.get("id") + "\">" + tab.get("name") + "</a></li>");

        //$(this.el_tabs).append("<li><a href='#category-" + itemView.model.get("id") + "'>"
            //+ itemView.model.get("name") + "</a></li>")
    }
});

我知道这有点难以理解,但你们是我的最后一招。模板和cateogry获取以及其他内容没有问题(在将CategoryCollectionView从Marionette集合转换为复合视图之前,它已经工作了。)

修改1

根据要求添加App initalizer:

            AllegroWidget = new Backbone.Marionette.Application();

            AllegroWidget.addInitializer(function (options) {

                // load templates and append them as scripts
                inject_template([
                        { id: "template-menuitem", path: "/js/templates/ordering-widget-menuitem.html" },
                        { id: "template-category", path: "/js/templates/ordering-widget-category.html" },
                        { id: "template-menu-core", path: "/js/templates/ordering-widget-menu-core.html" },
                        { id: "template-skeleton", path: "/js/templates/ordering-widget-skeleton.html" }
                    ]);

                // create app layout using the skeleton
                var AppLayout = Backbone.Marionette.Layout.extend({
                    template: "#template-skeleton",

                    regions: {
                        order_summary: "#order-summary",
                        categories: "#categories-content"
                    }
                });

                AllegroWidget.layout = new AppLayout();
                var layoutRender = AllegroWidget.layout.render();
                jQuery("#allegro-ordering-widget").html(AllegroWidget.layout.el);

                // Initialize the collection and views
                var _category_collection = new CategoryCollection();

                var _cateogories_view = new CategoryCollectionView({ api_key: window.XApiKey, collection: _category_collection });


                _category_collection.fetch({
                    beforeSend: function (xhr) {
                        xhr.setRequestHeader("X-ApiKey", window.XApiKey);
                    },
                    async: false
                });


                //AllegroWidget.addRegions({
                 ///   mainRegion: "#allegro-ordering-widget"
                //});
                AllegroWidget.layout.categories.show(_cateogories_view);

            });



            AllegroWidget.start({api_key: window.XApiKey});

2 个答案:

答案 0 :(得分:6)

在调用区域上的show之前,您将通过fetch添加到集合中。

默认情况下,Marionette.CompositeView会在模型添加到其集合时附加ItemViews。这是一个问题,因为itemViewContainer .tab-content尚未添加到dom,因为尚未在区域上调用show。

易于修复,重新编写代码如下所示,它应该可以工作而不会重载appendHtml。

// Initialize the collection and views
var _category_collection = new CategoryCollection();

// grab a promise from fetch, async is okay
var p = _category_collection.fetch({headers: {'X-ApiKey': window.XApiKey});

// setup a callback when fetch is done
p.done(function(data) {
   var _cateogories_view = new CategoryCollectionView({ api_key: window.XApiKey, collection: _category_collection });
   AllegroWidget.layout.categories.show(_cateogories_view);
}); 

答案 1 :(得分:0)

好的,这很奇怪,但在CategoryCollectionView类中添加它:

appendHtml: function (collectionView, itemView, index) {
    //@todo very weird stuff, assigning '.tab-content' to itemViewContainer should have been enough 
    collectionView.$(".tab-content").append(itemView.el);
}

解决了这个问题,但是我不知道它为什么会起作用,将'.tab-content'分配给itemViewContainer应该已经足够了,不知道吗?