ExtJS 5.1.1 Immediately fire binding in ViewModel

Exclaim picture Exclaim · Jul 28, 2015 · Viewed 8.5k times · Source

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

Answer

costa picture costa · Sep 8, 2018

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

Essentially the idea is that you listen to the bound variables changes instead of listening to the combobox 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('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'
            }]
        }
    }
});

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 : 'combo',
                    valueField: 'foo',
                    displayField: 'bar',
                    queryMode: 'local',

                    bind: {
                        store: '{combostore}',
                        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.