最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - ExtJS 5.1.1 Immediately fire binding in ViewModel - Stack Overflow

programmeradmin1浏览0评论

Seems like i have some misunderstanding with binding timings. I have a simple bobox 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:{
        bostore: {
            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 : 'bo',
                    valueField: 'foo',
                    displayField: 'bar',
                    queryMode: 'local',
                    bind: {
                        store: '{bostore}',
                        value: '{testObj.foo}'
                    },
                    listeners:{
                        change: 'onChange'
                    }

                }
            ]
        });
    }
});

Here's fiddle aswell:

Seems like i have some misunderstanding with binding timings. I have a simple bobox 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:{
        bostore: {
            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 : 'bo',
                    valueField: 'foo',
                    displayField: 'bar',
                    queryMode: 'local',
                    bind: {
                        store: '{bostore}',
                        value: '{testObj.foo}'
                    },
                    listeners:{
                        change: 'onChange'
                    }

                }
            ]
        });
    }
});

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

Share Improve this question asked Jul 28, 2015 at 16:35 ExclaimExclaim 731 silver badge7 bronze badges 3
  • I believe vm.notify() won't do its job synchronously. Note that adding delay: 1 option to the listeners config does the trick, even vm.notify() bees redundant. – Greendrake Commented Jul 29, 2015 at 1:21
  • If you have to use delay: 1 it should ring all bells you are doing something wrong. The same for calling notify() in this way.. – Tarabass Commented Jul 29, 2015 at 8:27
  • 1. By default a store has its autoSync config to false. You may have to set it to true for the boStore in your viewModel? | 2. You should not test the store in the onChange event of your bo because the bo hasn't the time to synchronize your store... | Remark: in extjs, you don't change the bo value, but the store content, so if you want to check any change in your bo, test it in its store – Michel Commented Sep 21, 2015 at 6:25
Add a ment  | 

4 Answers 4

Reset to default 2

I know it is a late response, however I think this problem is still relevant. See this fiddle: https://fiddle.sencha./#fiddle/2l6m&view/editor.

Essentially the idea is that you listen to the bound variables changes instead of listening to the bobox selection change (which triggers the re-evaluation of the bound variables).

The key code is in the constructor I added for the view model:

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('bobox selected item changed (bar value): ' + (value === null ? "null": value.get('bar')));
            console.log(me.getView().getController());
        });

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

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

and here is the view (note the binding to the selection):

Ext.application({
    name : 'Fiddle',

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

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

                    },
                    listeners:{
                        change: 'onChange'
                    }

                }
            ]
        });
    }
});

Binding the selection was not necessary but I included it anyway as another option because sometimes you may want to store additional data in the store that is bound to the list.

I hope this helps others.

You should not call notify directly on the viewmodel. It's private: http://docs.sencha./extjs/5.0/5.0.1-apidocs/#!/api/Ext.app.ViewModel-method-notify

Just set the data by calling 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
}

Never the less you could consider the following example, where I use a formula to get the selected model of the bobox. See that I removed the listener, added a reference to the bobox and created a formula to bind deep onto the selected record.

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:{
        bostore: {
            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 : 'bo',
                    reference: 'myCombo',
                    valueField: 'foo',
                    displayField: 'bar',
                    queryMode: 'local',
                    bind: {
                        store: '{bostore}',
                        value: '{testObj.foo}'
                    }/*,
                    listeners:{
                        change: 'onChange'
                    }*/
                },
                {
                    xtype: 'label',
                    bind: {
                        text: '{currentRecord.foo}'
                    }
                }
            ]
        });

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

Defer would be your savior:

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

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

Please use select event instead of change.

I think change event fires even before value is set.

发布评论

评论列表(0)

  1. 暂无评论