4

ContainerView他のビューを入れ替える があります。別のContainerViewものをコンテンツとして使用します。ネストされた をスワップインしようとすると、スワップContainerViewアウトした後、エラーが発生します: Uncaught Error: assertion failed: calling set on destroyed object

これがフィドルです: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();
4

1 に答える 1

2

問題は、インスタンス化select1していて、のメソッド内でselect2拡張するクラスを作成するときです。ContainerViewwidgetApp.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'),
...
}

widgetこれで、最初に DOM から削除したときに破棄された同じ 2 つのビューを再利用する代わりに、インスタンス化するたびに新しい子ビューを作成できます。

于 2013-02-28T01:35:34.813 に答える