ember.js – 将ContainerView交换进另一个ContainerView会导致被破坏的视图

我有一个ContainerView可以交换其他视图.我使用另一个ContainerView作为内容.在交换出来后,尝试交换嵌套的ContainerView会导致错误:Uncaught Error:断言失败:在被破坏的对象上调用set.

这是小提琴:http://jsfiddle.net/hekevintran/bFSKD/

要发生错误,请单击“其他表单”,然后单击“第一个表单”.

我认为错误是因为从ContainerViews中删除的视图被破坏,并且不会重新创建嵌套ContainerView的子视图.修复这个例子的正确方法是什么?

模板:

<script type="text/x-handlebars" data-template-name="box">
<div>
    {{#each forms}}
        <button {{action "selectForm" this }}>{{this.name}}</button>
    {{/each}}
    {{view container}}
</div>
</script>

<script type="text/x-handlebars" data-template-name="form">
    <form>
        {{#each fields}}
            <div>
                {{this.label}}: {{view this.widget}}
            </div>
        {{/each}}
    </form>
</script>

JavaScript的:

App = Ember.Application.create({});

App.BoxController = Ember.Object.extend({
    initialForm: null,
    currentForm: null,
    init: function () {
        var form = this.get('initialForm');
        this.set('currentForm', form);
        this.get('container').set('currentView', form.get('view').create());
    },
    forms: [],
    container: function () {
        return Ember.ContainerView.create({
            boxController: this,
            controllerBinding: 'boxController.currentForm'
        })
    }.property(),
    selectForm: function (form) {
        this.set('currentForm', form);
        this.get('container').set('currentView', form.get('view').create());
    }
});

App.Field = Ember.Object.extend({
    value: null,
    widgetBaseClass: Ember.TextField,
    widget: function () {
        return this.get('widgetBaseClass').extend({
            field: this,
            valueBinding: 'field.value'
        });
    }.property('widgetBaseClass')
});

App.RangeField = App.Field.extend({
    widget: function () {
        var field = this;
        return Ember.ContainerView.extend({
            childViews: [field.get('select1').create(), field.get('select2').create()]
        });
    }.property('select1', 'select2'),
    fromValue: null,
    toValue: null,
    value: function () {
        return [this.get('fromValue.value'), this.get('toValue.value')];
    }.property('fromValue', 'toValue'),
    choices: [
        '1',
        '2',
        '3',
        '4'
    ],
    remainingChoices: function () {
        var fromValue = this.get('fromValue');
        if (fromValue) {
            var choices = this.get('choices');
            var index = choices.indexOf(fromValue);
            return choices.slice(index + 1);
        }
        return [];
    }.property('fromValue', 'choices'),
    select1: function () {
        return Ember.Select.extend({
            field: this,
            valueBinding: 'field.fromValue',
            contentBinding: 'field.choices'
        });
    }.property(),
    select2: function () {
        return Ember.Select.extend({
            field: this,
            valueBinding: 'field.toValue',
            contentBinding: 'field.remainingChoices',
            contentHasChangedOnce: false,
            contentChanged: function () {
                // Set the initial value only once
                if (! this.get('contentHasChangedOnce')) {
                    this.set('contentHasChangedOnce', true);
                    this.set('value', this.get('content')[0]);
                }

                // Reset the value if the chosen value is no longer
                // available
                if (! this.get('content').contains(this.get('value'))) {
                    this.set('value', this.get('content')[0]);
                }
            }.observes('content')
        });
    }.property()
});

App.Form = Ember.Object.extend({
    fieldNames: [],
    fields: function () {
        var that = this;
        var out = [];
        _.each(this.get('fieldNames'), function (fieldName) {
            out.pushObject(that.get(fieldName));
        });
        return out;
    }.property('fieldNames')
});

aForm = App.Form.create({
    name: 'First Form',
    fieldNames: [
        'a',
        'b'
    ],
    a: App.Field.create({label: 'A'}),
    b: App.RangeField.create({label: 'B'}),
    view: Ember.View.extend({
        templateName: 'form'
    })
});

var boxController = App.BoxController.create({
    initialForm: aForm,
    forms: [
        aForm,
        Ember.Object.create({
            name: 'Other Form',
            view: Ember.View.extend({
                template: Ember.Handlebars.compile('Foobar')
            })
        })
    ]
});

var boxView = Ember.View.create({
    templateName: 'box',
    controller: boxController
});

boxView.append();

最佳答案 问题是,当您在App.RangeField的widget方法中创建扩展ContainerView的类时,您正在实例化select1和select2.

更改此代码:

App.RangeField = App.Field.extend({
    widget: function () {
        var field = this;
        return Ember.ContainerView.extend({
            childViews: [field.get('select1').create(), field.get('select2').create()]
        });
    }.property('select1', 'select2'),
    ...
}

对此:

App.RangeField = App.Field.extend({
    widget: function () {
        var field = this;
        return Ember.ContainerView.extend({
            init: function() {
                this.set('childViews', [field.get('select1').create(), field.get('select2').create()]);
                this._super();
            }
        });
    }.property('select1', 'select2'),
...
}

现在,每次实例化窗口小部件时都会创建新的子视图,而不是重新使用第一次从DOM中删除它们时销毁的相同视图.

点赞