【问题标题】:Passing a JSon object to a Marionette composite View将 JSON 对象传递给 Marionette 复合视图
【发布时间】:2013-09-05 04:55:11
【问题描述】:

我有一个显示对象列表的简单表,但是我想传递一个布尔值,以便如果用户登录他可以看到 [edit] 按钮,我尝试将参数作为 listItem 传递,但是不能,有人能解释一下吗?

澄清:我希望能够从模板内部访问值

       var TableView = {};

    TableView.RowItemView = Marionette.ItemView.extend({
        tagName: "tr",
        template:$('#table-template-item').html(),

        //if required add events and triggers here.
        events: {
            "click td a.js-show": "showClicked",
            "click td a.js-edit": "editClicked"
            }

       });

    TableView.MainTable = Marionette.CompositeView.extend({
        tagName: "table",
        className: "table table-hover",
        template: $('#table-template').html() ,
        itemView: TableView.RowItemView,
        itemViewContainer: "tbody"

    });

   return TableView;

    InitialController.home = function () {
    console.log("initializing application layout");
    var list = new PropertiesModel.ContactCollection;
    list.fetch({reset: true});
    var tableView = new TableView.MainTable({
        collection: list
    });

    app.mainRegion.show(tableView);

};

【问题讨论】:

    标签: javascript json backbone.js marionette


    【解决方案1】:

    我假设在您的应用程序中的某个地方,您可以知道用户是否已登录。为了论证,我假设它被封装在一个附加到用户对象的函数中,该对象又附加到全局应用程序,所以MyApp.CurrentUser.isLoggedIn()

    您可以采取的一种方法是在RowItemView 和此CurrentUser 对象之间添加依赖关系。当您渲染RowItemView 测试用户是否已登录并相应地更新视图时。

    我在这里对你的代码做了很多假设,但是这个 sn-p 应该演示基本思想:

      onRender: function() {
        if (MyApp.CurrentUser.isLoggedIn()) {
          this.$('.js-edit').removeClass('hidden');
        }
      }
    

    附录

    那么,您想更新视图的多个部分吗?尝试使用 templateHelpers 属性:

    TableView.RowItemView = Marionette.ItemView.extend({
    
      template: /* resolves to: */ '<td><%= getItemOne() %></td>' +
                                 '<td><%= getItemTwo() %></td>',
      templateHelpers: {
        getItemOne: function() {
            if (window.isLoggedIn) {
                return 'Logged In Content';
            }
            return 'Not Logged In Content';
        },
        getItemTwo: function() {
            if (window.isLoggedIn) {
                return 'Logged In Content';
            }
            return 'Not Logged In Content';
        }
    }
    

    既然您说isLoggedIn 在全局命名空间中,则无需传入。如果需要传入,请尝试:

    TableView.RowItemView = Marionette.ItemView.extend({
      initialize: function(options) {
        this.templateHelpers.isLoggedIn = options.isLoggedIn;
        // ... other work as needed
      },
      templateHelpers: {
        getItemOne: function() {
            if (this.isLoggedIn) {} // should work now
        }
      }
    

    这种方法的问题是您从 CompositeView 传递一个变量,这意味着您需要覆盖 CompositeView 的 buildItemView 属性,坦率地说,这似乎比它的价值更多,但如果您愿意,这里有一个片段试试看:

    TableView.MainTable = Marionette.CompositeView.extend({
      initialize: function(collection, options) {
        this.isLoggedIn = options.isLoggedIn;
        // ...
      },
      buildItemView: function(item, ItemViewType, itemViewOptions){
        var options = _.extend({model: item, isLoggedIn: this.isLoggedIn }, itemViewOptions);
        return new ItemViewType(options);
      },
    

    【讨论】:

    • 你好克里斯,是的,我有一个全局变量来说明用户是否登录,问题是我想要一个包含一些 语句的模板,但是我将我的模型传递给 rowItemView,所以我不知道如何将我的用户对象传递给它。
    • 啊。您是否尝试过使用templateHelpers?我会用一个例子来更新我的答案。
    【解决方案2】:

    您可以将ItemViewOptions 作为函数(动态)或对象(静态)提供给复合/集合视图呈现的每个项目视图

    https://github.com/marionettejs/backbone.marionette/blob/master/docs/marionette.collectionview.md#collectionviews-itemviewoptions

    TableView.MainTable = Marionette.CompositeView.extend({
        itemViewOptions: function(){
            return {
                isLoggedIn: //true/false
            };
        },
        //snip...
    }
    

    CollectionView/CompositeView 中设置后,您可以通过在ItemView 中执行以下操作来获取它们:

    initialize: function(options){
        var x = options.isLoggedIn;
    }
    

    编辑:或者,在模板中查看它&lt;%=isLoggedIn%&gt;

    initialize: function(options){
        this.model.set('isLoggedIn', options.isLoggedIn || false);
    }
    

    【讨论】:

    • 您好 Scott,我曾尝试过类似的方法,问题是我无法将该值传递给我的模板,当我尝试访问模板上的 isLogged 时,我收到未定义的错误消息。
    • 您需要将 isLoggedIn 变量放入模型中,以便模板引擎 (this.model.set('isLoggedIn', options.isLoggedIn || false)) 读取它。如果是这种情况,那么您可能想在CompositeView/CollectionView 中执行此操作,然后放弃 itemViewOptions。由你决定!
    • 此外,Marionette 具有内置功能,只需提供一个字符串即可处理模板。所以不用写template: $('#table-template').html(),你只需要写template: #table-template'
    • 我反对向模型添加 isLoggedIn 属性,因为它可能会破坏关注点分离 - 例如如果模型描述了一个产品,那么 Product 模型知道用户是否登录是没有意义的。这就是 Marionette 视图支持 templateHelpers 的原因。
    • Scott 非常感谢您的帮助,但我同意 chris 的观点,特别是如果我已经将该模型用于其他用途。
    【解决方案3】:

    似乎每一行都是可编辑或不可编辑的。所以这是我认为更适合您需求的另一个答案。它将防止您必须在每个 ItemView 中传递一个选项和执行逻辑,但将涉及必须有另一个视图类型

    TableView.RowItemView = Marionette.ItemView.extend({
        template:'#table-template-item',
        //...snip
    });
    
    TableView.EditableRowItemView = TableView.RowItemView.extend({
        template:'#editable-table-template-item',
    });
    
    TableView.MainTable = Marionette.CompositeView.extend({
        initialize: function(){
            if(isLoggedIn){ //true/false
                this.itemView = TableView.EditableRowItemView
            }
        },
        itemView: TableView.RowItemView
    }
    

    EditableRowItemView 扩展自 TableView.RowItemView,因为它们的逻辑基本相同,但模板不同(可能还有一些额外的编辑逻辑)

    【讨论】:

    • 虽然问题还不是很清楚,但 OP 在他的 cmets 中解释说,他希望根据用户是否登录有条件地在每个 ItemView 中插入项目。
    猜你喜欢
    • 2016-10-15
    • 2013-07-20
    • 2016-07-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多