Javascript ExtJS 5.1.1立即在ViewModel中激活绑定

Javascript ExtJS 5.1.1立即在ViewModel中激活绑定,javascript,extjs,mvvm,data-binding,extjs5,Javascript,Extjs,Mvvm,Data Binding,Extjs5,似乎我对绑定时间有一些误解。我有一个简单的组合框,其值绑定到viewmodel中的某个对象。选择新值,触发更改事件,该事件在setValue方法之后触发,因此我的新值已设置,但我的viewmodel尚未更新。何时更新我的viewmodel?我找到了一些关于scheduler的信息,上面说我需要运行notify()方法来立即将更改应用到viewmodel,但这对我毫无帮助 Ext.define('MyModel', { extend: 'Ext.data.Model', idPro

似乎我对绑定时间有一些误解。我有一个简单的组合框,其值绑定到viewmodel中的某个对象。选择新值,触发更改事件,该事件在setValue方法之后触发,因此我的新值已设置,但我的viewmodel尚未更新。何时更新我的viewmodel?我找到了一些关于scheduler的信息,上面说我需要运行notify()方法来立即将更改应用到viewmodel,但这对我毫无帮助

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'
                    }

                }
            ]
        });
    }
});

还有小提琴:

您不应该直接在viewmodel上调用notify。这是私人的:

只需通过调用vm.setData({})来设置数据

你可以考虑下面的例子,在这里我使用一个公式来获得组合框的选择模型。请注意,我删除了侦听器,添加了对组合框的引用,并创建了一个公式来绑定到所选记录的深度

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'}});
    }
});

延迟将是你的救星:

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

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

请使用
选择
事件,而不是
更改


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

我知道这是一个延迟响应,但我认为这个问题仍然相关。看到这把小提琴了吗

从本质上讲,这个想法是,您监听绑定变量的更改,而不是监听组合框选择的更改(这会触发绑定变量的重新计算)

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

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'
            }]
        }
    }
});
下面是视图(注意绑定到选择):

绑定选择是没有必要的,但我还是将其作为另一个选项包括在内,因为有时您可能希望在绑定到列表的存储中存储其他数据


我希望这能帮助其他人。

我相信
vm.notify()
不会同步完成它的工作。请注意,将
delay:1
选项添加到侦听器配置中会起到作用,即使
vm.notify()
也会变得多余。如果必须使用
delay:1
它应该会提醒所有人你做错了什么。以这种方式调用
notify()
也是如此..1。默认情况下,存储的
autoSync
config设置为false。对于viewModel中的comboStore,您可能必须将其设置为true2.您不应该在组合的onChange事件中测试存储,因为组合没有时间同步您的存储…|备注:在extjs中,您不会更改组合值,但会更改存储内容,因此,如果您想检查组合中的任何更改,请在其存储中进行测试。谢谢回复,但我不想手动使用
setData()
或创建公式来修复此简单绑定。我只想知道,调用
setValue()
后,我的viewmodel何时准备就绪,以及为什么要将
delay:1
buffer:1
添加到侦听器配置中,这将实现访问combobox change事件中的值的技巧,如@DrakeES所述。我想我应该在viewmodel中查看
Ext.util.Scheduler
,因为我发现了一些有趣的配置,比如
tickDelay:5
,默认设置为5毫秒。然后,在为将执行下一个notify.TickDelay的计时器创建延迟函数时使用的配置确实用于此。不幸的是,我没有发现将TickDelay设置为更高的值非常有用,因为它设置为整个viewmodel。而且我相信它是私人的,所以你不能依赖它的存在。。
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'
                    }

                }
            ]
        });
    }
});