ExtJS 5.1.1 Immediately fire binding in ViewModel

时间:2015-07-28 16:35:45

标签: javascript extjs mvvm data-binding extjs5

Seems like i have some misunderstanding with binding timings. I have a simple combobox with value binded to some object in viewmodel. Selecting new value, firing change event, which fired after setValue method, so my new value is already set, but my viewmodel is not updated yet. When my viewmodel will be updated? I found some information about scheduler, which says i need to run notify() method to immediately apply changes to viewmodel, but it doesn't help me at all.

Ext.define('MyModel', {
    extend: 'Ext.data.Model',
    idProperty: 'foo',
    fields: [{
        name: 'bar',
        type: 'string'
    }]
});

Ext.define('MyViewModel',{
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.my',
    data: {
        testObj: {
            foo: null,
            bar: null
        }
    },
    stores:{
        combostore: {
            model: 'MyModel',
            data: [{
                foo: '1',
                bar: 'qwerty'
            },{
                foo: '2',
                bar: 'ytrewq'
            }]
        }
    }
});

Ext.define('MyViewController', {
    extend: 'Ext.app.ViewController',
    alias: 'controller.my',
    onChange: function() {
        var vm = this.getViewModel();
        vm.notify();
        console.log(vm.get('testObj.foo'));//supposed to be current value
    }
});

Ext.application({
    name : 'Fiddle',

    launch : function() {
        Ext.create('Ext.container.Viewport', {
            controller: 'my',
            viewModel: {
                type: 'my'
            },
            layout : 'vbox',
            items : [
                { 
                    xtype : 'combo',
                    valueField: 'foo',
                    displayField: 'bar',
                    queryMode: 'local',
                    bind: {
                        store: '{combostore}',
                        value: '{testObj.foo}'
                    },
                    listeners:{
                        change: 'onChange'
                    }

                }
            ]
        });
    }
});

Here's fiddle aswell: https://fiddle.sencha.com/#fiddle/r88

4 个答案:

答案 0 :(得分:2)

我知道这是一个较晚的答复,但是我认为这个问题仍然很重要。看到这个小提琴:https://fiddle.sencha.com/#fiddle/2l6m&view/editor

本质上是,您要听绑定变量的变化,而不是听组合框选择的变化(这会触发对绑定变量的重新评估)。

关键代码在我为视图模型添加的构造函数中:

Ext.define('MyViewModel',{
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.my',

    // added this to enable the binding
    constructor: function () {
        var me = this;
        me.callParent(arguments);

        me.bind('{selectedItem}', function (value) {
            console.log('combobox selected item changed (bar value): ' + (value === null ? "null": value.get('bar')));
            console.log(me.getView().getController());
        });

        me.bind('{testObj.foo}', function (value) {
            console.log('combobox value (foo value): ' + value);

            // you can access the controller
            console.log(me.getView().getController());
        });
    },
    data: {
        testObj: {
            foo: null,
            bar: null
        },
        selectedItem: null,
    },
    stores:{
        combostore: {
            model: 'MyModel',
            data: [{
                foo: '1',
                bar: 'qwerty'
            },{
                foo: '2',
                bar: 'ytrewq'
            }]
        }
    }
});

这是视图(请注意所选内容的绑定):

Ext.application({
    name : 'Fiddle',

    launch : function() {
        Ext.create('Ext.container.Viewport', {
            controller: 'my',
            viewModel: {
                type: 'my'
            },
            layout : 'vbox',
            items : [
                {
                    xtype : 'combo',
                    valueField: 'foo',
                    displayField: 'bar',
                    queryMode: 'local',

                    bind: {
                        store: '{combostore}',
                        value: '{testObj.foo}',
                        selection: '{selectedItem}'

                    },
                    listeners:{
                        change: 'onChange'
                    }

                }
            ]
        });
    }
});

绑定选择不是必需的,但是我还是把它作为另一个选择包括进来,因为有时您可能想在绑定到列表的商店中存储其他数据。

我希望这对其他人有帮助。

答案 1 :(得分:0)

您不应直接在viewmodel上调用notify。它是私人的: http://docs.sencha.com/extjs/5.0/5.0.1-apidocs/#!/api/Ext.app.ViewModel-method-notify

只需调用vm.setData({})即可设置数据。

onChange: function(cb, newValue, oldValue) {
    var vm = this.getViewModel();

    console.log('newValue', newValue);
    console.log('oldValue', oldValue);
    this.getViewModel().setData({'testObj': {'foo': newValue}});
    console.log(vm.get('testObj.foo'));//supposed to be current value
}

从来没有考虑过以下示例,我使用公式来获取组合框的选定模型。看到我删除了监听器,添加了对组合框的引用并创建了一个公式以深入绑定到所选记录。

Ext.define('MyModel', {
    extend: 'Ext.data.Model',
    idProperty: 'foo',
    fields: [{
        name: 'bar',
        type: 'string'
    }]
});

Ext.define('MyViewModel',{
    extend: 'Ext.app.ViewModel',
    alias: 'viewmodel.my',
    data: {
        testObj: {
            foo: null,
            bar: null
        }
    },
    stores:{
        combostore: {
            model: 'MyModel',
            data: [{
                foo: '1',
                bar: 'qwerty'
            },{
                foo: '2',
                bar: 'ytrewq'
            }]
        }
    },

    formulas: {
        currentRecord: {
            bind: {
                bindTo: '{myCombo.selection}',
                deep: true
            },
            get: function(record) {
                return record;
            },
            set: function(record) {
                this.set('currentRecord', record);
            }
        }
    }
});

Ext.define('MyViewController', {
    extend: 'Ext.app.ViewController',
    alias: 'controller.my',
    onChange: function(cb, newValue, oldValue) {
        var vm = this.getViewModel();

        console.log('newValue', newValue);
        console.log('oldValue', oldValue);
        this.getViewModel().setData({'testObj': {'foo': newValue}});
        console.log(vm.get('testObj.foo'));//supposed to be current value
    }
});




Ext.application({
    name : 'Fiddle',

    launch : function() {
        var vp = Ext.create('Ext.container.Viewport', {
            controller: 'my',
            viewModel: {
                type: 'my'
            },
            layout : 'vbox',
            items : [
                { 
                    xtype : 'combo',
                    reference: 'myCombo',
                    valueField: 'foo',
                    displayField: 'bar',
                    queryMode: 'local',
                    bind: {
                        store: '{combostore}',
                        value: '{testObj.foo}'
                    }/*,
                    listeners:{
                        change: 'onChange'
                    }*/
                },
                {
                    xtype: 'label',
                    bind: {
                        text: '{currentRecord.foo}'
                    }
                }
            ]
        });

        /* Just an example. You could also select records on the combo itself */
        vp.getViewModel().setData({'testObj': {'foo': '2'}});
    }
});

答案 2 :(得分:0)

Defer将成为你的救世主:

onChange: function() {
    var vm = this.getViewModel();

    Ext.defer(function(){
       console.log(vm.get('testObj.foo'));//supposed to be current value
    },10,this);
}

答案 3 :(得分:0)

请使用select事件代替change

我认为更改事件甚至会在设置值之前触发。