ember.js - 在另一个容器 View 内外交换容器 View 会导致 View 被破坏

标签 ember.js

我有一个 ContainerView交换其他 View 的进出。我用另一个 ContainerView作为内容。试图交换嵌套 ContainerView ,在我把它换掉后,导致错误:Uncaught Error: assertion failed: calling set on destroyed object .

这是 fiddle :http://jsfiddle.net/hekevintran/bFSKD/

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

我认为错误是因为从 ContainerViews 中删除了 View 被破坏,嵌套的 subview 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();

最佳答案

问题是您正在实例化 select1select2当您创建扩展 ContainerView 的类时内widget App.RangeField的方法.

更改此代码:

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'),
...
}

现在每次实例化时都会创建新的 subview widget而不是重新使用第一次从 DOM 中删除它们时被破坏的相同的两个 View 。

关于ember.js - 在另一个容器 View 内外交换容器 View 会导致 View 被破坏,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14932914/

相关文章:

json - 处理路由时出错 : index Assertion Failed: You must include an 'id'

ember.js - 定义复杂模型

javascript - Ember.js - Pod 结构中的错误状态

ember.js - 有没有办法使用 emberjs 创建登录/注册而不需要任何插件?

javascript - Ember.js - 组件内部模型

ember.js - Ember : accessing {{render}} options hash in controller

ember.js - Ember 数据剩余适配器错误处理不起作用

ember.js - Ember.Application.create : addressing the created instances of controllers/routers/views etc 之后

javascript - Ember 应用警报

javascript - app/utils 中用于 ember-cli 应用程序的单元测试模块