使用带选择标记的Marionette CompositeView时获取所选选项

时间:2015-07-29 06:55:14

标签: jquery backbone.js marionette

我使用CompositeView显示选择标记,并使用CompositeView的集合呈现选项。

OptionView = Marionette.ItemView.extend({
    template: ...
    tagName: "option",
  }
});

SelectView = Marionette.CompositeView.extend({
    template: ...           
    childView: OptionView,
    childViewContainer: "select",       

    triggers: {
        "change @ui.select": "do:something"
    },

    ui:{
        select: "[ui-select]"
    },
});

奇怪的是,当我尝试从包含SelectView的LayoutView中获取所选选项时,我得到了不一致的行为:

EditActivities.LayoutView = Marionette.LayoutView.extend({
    template: ...
    regions: ...

    onChildviewDoSomething: function(view){
        console.log(view.ui.select.val());
    }
})

当我在浏览器上更改select标记的值时,有时记录到控制台的是选项标记的内部HTML,有时它会记录该值。这就是我的OptionView模板:

<option value="<%=id%>"><%= name %></option>

我对这种不一致的行为感到有点困惑。想法?

3 个答案:

答案 0 :(得分:1)

我明白了。问题出在OptionView我指定tagName是“选项”。在模板中,我还有选项标记,它实际上创建了一组嵌套选项标记。这就是造成不可预测行为的原因。

我改了它,所以我的模板现在只是:

<%= name %>

我现在遇到的问题是如何设置选项标签的value属性,因为现在它会产生和选项标签,每个项目都没有值。我目前的解决方法是在视图上添加一个初始化函数,如下所示:

initialize : function (options) {
  this.$el.attr("value",this.model.attributes.id);
}

但如果有更好的方法,我肯定愿意接受......

答案 1 :(得分:1)

要包含选项的value属性以及innerHTML而不必在初始化中修改内容,可以使用Backbone的属性哈希,如下所示:

SelectView = Marionette.CompositeView.extend({
  tagName: 'option',
  template: _.template('<%= name %>'),
  attributes: function() {
    return {
      'value': this.model.id
    };
  }
});

答案 2 :(得分:0)

正如BaskingShark所提到的,属性hash可用于指定选项元素的属性。 项目视图可用于选项元素。

var OptionView = Marionette.ItemView.extend({
    tagName: 'option',
    attributes: function () {
        return {
            'value': this.model.get('id')
        }
    },
    template: _.template('<%= name %>')
});

使用项目视图的集合视图可用于选择标记。

var SelectOptionsView = Marionette.CollectionView.extend({
    childView: OptionView
});

可以在布局视图的区域内呈现集合视图,也可以在其中侦听select标记上的事件。 举个例子:http://jsfiddle.net/95g1ojwk/3/

var pills = new Backbone.Collection([{
    id: '',
    name: 'Choose'
}, {
    id: 'illusion',
    name: 'Blue'
}, {
    id: 'reality',
    name: 'Red'
}]);

var OptionView = Marionette.ItemView.extend({
    tagName: 'option',
    attributes: function () {
        return {
            'value': this.model.get('id')
        }
    },
    template: _.template('<%= name %>')
});

var SelectOptionsView = Marionette.CollectionView.extend({
    childView: OptionView
});

var MyLayoutView = Mn.LayoutView.extend({
    ui: {
        destiny: "#destiny",
        choice: '#choice'
    },
    regions: {
        "options": "#options-region",
    },
    events: {
        'change @ui.choice': 'chosenDestiny'
    },
    onRender: function () {
        this.showChildView('options', new SelectOptionsView({
            collection: pills,
            el: this.ui.choice
        }));
    },
    chosenDestiny: function (event) {
        if($(event.target).val()==='reality'){
            this.ui.destiny.text('Nothing but Truth!');
        } else if($(event.target).val()==='illusion'){
            this.ui.destiny.text('The Story Ends!');
        } else {
            this.ui.destiny.text('This is your last chance!');
        }
    }
});

new MyLayoutView({
    el: '#app',
    template: '#layout-template'
}).render();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="http://underscorejs.org/underscore.js"></script>
<script src="http://backbonejs.org/backbone.js"></script>
<script src="http://marionettejs.com/downloads/backbone.marionette.js"></script>
<script type="text/template" id="layout-template">
    <div id="options-region">
        <select id="choice"></select>
    </div > 
    <label id = "destiny" > </label>
</script>
<script type="text/template" id="image-template">
    <div class = "sizer" > <img src = "http://placehold.it/<%= width %>x<%= height %>" /> </div>
</script>
<div id="app"></div>