【问题标题】:CollectionView - collection data not being passed to childViewCollectionView - 集合数据未传递给 childView
【发布时间】:2015-06-19 23:42:39
【问题描述】:

我正在尝试使 collectionView 工作,但我不确定 CollectionView 是否会自动启动 fetch 方法,然后用获取的数据填充 ChildViews。还是我需要手动做的事情?我检查了 Marionette 文档页面,但找不到任何可以回答我的问题的合适示例。

下面的例子是我目前得到的,集合中填满了所有需要的数据,但由于某种原因数据没有传递给 childview。

每当我调用“http://localhost/GetCategories”时,都会返回以下 JSON:

JSON 数据:

[{"category_id":"Category1","category_name":"Category One"}, 
 {"category_id":"Category2","category_name":"Category Two"}]

收藏:

  define([ 'underscore',  'backbone',  'models/MainMenu/MM.model.category'], function(_, Backbone, m_Category){
      var CategoriesCollection = Backbone.Collection.extend({
        model: m_Category,

        url : 'GetCategories';

        initialize: function() {
            console.log('CategoriesCollection initialized...');
            this.fetch()
        }

      });


  return CategoriesCollection;
});

collectionView:

define([ 'backbone', 'underscore', 'marionette', 
    'collections/MainMenu/collection.categories' , 
    'layouts/MainMenu/itemview.category'], 
    function (Backbone, _, Marionette, c_Categories, iv_Category) {
    "use strict";
    var CategoriesCollectionView = Marionette.CollectionView.extend({

        tagName: 'div',

        template: null,

        id: 'categories',

        childView: iv_Category,

        collection : new c_Categories(),

        initialize: function(){
            console.log('Categories Collection: initialized');

            /// or should I call fetch() from within the CV? 
            /// but how do I then pass all the data to ChildView? 
            this.collection.fetch().done(function(){

            })
        },
        onRender: function(){
            console.log(this.collection) ///<-- shows all the JSON data properly
        },
        onShow: function(){
        }
    });

    return CategoriesCollectionView;
});

项目视图:

define([ 'backbone', 'underscore', 'marionette', 'templates/template.mainmenu'], function (Backbone, _, Marionette, template) {
    "use strict";
    var CategoryView = Marionette.ItemView.extend({

        tagName: 'div',

        template: template['category.layout'],

        id: 'category-layout',

        initialize: function(){
            console.log('Category Layout: initialized');
        },
        onRender: function(){
            console.log(this.model) /// < --- doesn't return anything 
        },
        onShow: function(){
            console.log(this.model) ///< --- doesn't return anything 
        }
    });

    return CategoryView;
});

它仅在我在 CollectionView 之上创建一个 LayoutView 并从那里处理获取和分配集合时才有效。

define([ 'backbone', 'underscore', 'marionette', 
            'templates/template.mainmenu', 
            'collections/MainMenu/MM.collection.categories',
            'layouts/MainMenu/collectionview.categories'    ],
    function (Backbone, _, Marionette, template, c_Categories, cv_Categories) {
    "use strict";
    var CategoryLayoutView = Marionette.LayoutView.extend({


        template: template['categories.layout'],

        regions: {
            categories : '#categories'
        },

        id: 'categories-layout',

        initialize: function(options){
            this.collection = new c_Categories();
            console.log('Category Layout: initialized');
        },

        onRender: function(){
            var categories = this.categories
            var collection = this.collection;
            collection.fetch().done(function(cData){
                categories.show(new cv_Categories({collection : collection}))
            })
        },

        onShow: function(){
        }
    });

    return CategoryLayoutView;
});

任何帮助将不胜感激。

谢谢

【问题讨论】:

  • 可以在CollectionView的initialize方法中试试this.collection = new c_Categories()吗?因为否则看起来还可以。顺便说一句,tagName: 'div' 是多余的,它是默认值。
  • 也试过了,但结果是一样的:/

标签: javascript backbone.js marionette


【解决方案1】:

Prelimnaries:Collection/CompositeView 的主要目的是正确渲染 Backbone.Collection,即将集合模型传递给 CollectionView 子项,并渲染这些子项。除了为 Collection/CompositeView 提供 - 这是关键 - 一个 pre 填充的集合之外,您无需参与。

现在,您遇到的问题是您正在对 CategoriesCollection.initialize() 进行异步获取(默认情况下,所有 AJAX 调用都是异步的)。由于在定义 CategoriesCollectionView 时调用了该初始化(请参阅其 collection 属性),因此在渲染它时可能不会及时返回。因此,CollectionView 呈现,但没有找到模型,并且仅呈现 emptyView(如果已提供)。

您有两个选择:在 LayoutView 中执行您正在执行的操作(这不仅是我在视图中一直执行的操作,而且我已经与一些顶级 Marionette 贡献者进行了交谈他们也这样做),或者同步获取(出于性能原因,我不推荐这样做)。

几点建议

  1. 从CategoriesCollection.initialize() 中删除提取(如果您想保留它,您必须在提取中传递选项{ async: false },以保证在您呈现视图时数据将返回. 但是,我不建议这样做,因为您在等待获取时会阻塞 CPU)。

  2. 从 CategoriesCollectionView 定义中删除 CategoriesCollectionView.collection 属性。相反,我们将从父 LayoutView 传递集合

  3. 我建议您使用 .then() 而不是 .done() 作为 Promise 处理程序。两个原因:

    一个。 .then() 更好地处理错误:如果错误不受管理,它将显示堆栈跟踪,并且第二个参数始终可用于实际处理由 Promise 导致的错误。 湾。 .then() 允许您继续链接。也许不是在这个调用中,但是在其他一些 Promise 中你可能想在调用进来之后调用一系列回调。就像名字暗示的那样 .done() 是回调链的末端

除此之外,您的解决方案是最佳实践。

【讨论】:

  • 感谢您的意见。我仍然需要异步加载集合,所以我会坚持我到目前为止提出的解决方案。
  • 我完全同意。您的解决方案遵循最佳做法
  • 但是,您应该考虑第 1 点和第 2 点。您会意识到自己做了不必要的工作。
  • 是的,我确实按照您的建议更正了那个。关于1点,这个参数不是同步获取吗?这不是以后会导致性能问题的原因吗?
  • 这一点在其他两个上下文中不清楚。我不想鼓励同步获取的做法。我会重写的。
【解决方案2】:

Marionette.CollectionView 的示例 - jsfiddle

//Collection View
var CollectionView = Marionette.CollectionView.extend({
    template: "#coll-template",
    childView: MainView,
    itemViewContainer: "#items"
});

//Item View    
var MainView = Marionette.ItemView.extend({
    template: "#sample-template",
    templateHelpers: function() {
        return {
            id: this.model.id
        };
    },
    onDomRefresh: function() {
        console.log("DOM REFRESH OF ITEM");
    }
});

//Creating some models
var model = new Backbone.Model({
    contentPlacement: "here",
    id: 1
});
var model2 = new Backbone.Model({
    contentPlacement: "here",
    id: 2
});
var model3 = new Backbone.Model({
    contentPlacement: "here",
    id: 3
});

//Create collection and resetting it with created models
var collection = new Backbone.Collection();
collection.reset([model, model2, model3]);


var view = new CollectionView({
    collection: collection
});

【讨论】:

  • 感谢您分享示例,但我希望看到一个您可以从 JSON 文件或任何其他来源获取所有必需数据而不是使用预定义数据的地方..
  • 我已根据您所需的更改更新了我的小提琴,希望这对您有所帮助。 Fiddle Link
  • 所以一旦我调用 this.collection.fetch() ,然后在“成功”选项中我可以添加 this.collection.reset(this.collection) 对吗?
  • 顺便说一句,是否可以在collectionview中定义backbone.collection?
  • 在你的情况下,你可以简单地写 this.collection.reset();在您的成功选择中。除非您想手动使用模型数组重置该集合,否则无需将任何内容传递给重置方法。
【解决方案3】:

您需要从您的集合视图中传递 childViewOptions。

例子:

define([ 'backbone', 'underscore', 'marionette', 
    'collections/MainMenu/collection.categories' , 
    'layouts/MainMenu/itemview.category'], 
    function (Backbone, _, Marionette, c_Categories, iv_Category) {
    "use strict";
    var CategoriesCollectionView = Marionette.CollectionView.extend({

        tagName: 'div',

        template: null,

        id: 'categories',

        childView: iv_Category,

        collection : new c_Categories(),

        childViewOptions : function(){
            return{
                collection: this.collection
            }
        },

        initialize: function(){
            console.log('Categories Collection: initialized');

            /// or should I call fetch() from within the CV? 
            /// but how do I then pass all the data to ChildView? 
            this.collection.fetch().done(function(){

            })
        },
        onRender: function(){
            console.log(this.collection) ///<-- shows all the JSON data properly
        },
        onShow: function(){
        }
    });

    return CategoriesCollectionView;
});

并且在您的项目视图中,您可以在初始化方法中获取从集合视图传递的每个集合模型。


项目视图中的初始化方法示例:

initialize: function(options){
            console.log('Category Layout: initialized');
            console.log(options.model);
        },

【讨论】:

  • 但子视图不应该自动填充集合数据吗?
  • 它将自动填充,但 itemView 应该知道要使用哪个集合,因此我们将它传递给 childViewOptions,并且该集合中将存在许多模型,因此将自动填充许多子视图。
  • childViewOptions 用于将数据从 collectionView 传递到 itemView,但不是强制要求通过它传递集合。
  • 尽管它可以工作,但它似乎有点 hacky...我敢肯定有更好的方法。这样做..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-06
  • 2023-03-24
  • 1970-01-01
  • 2014-10-26
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多