0

I created this fiddle where you can see what happens: https://fiddle.sencha.com/#view/editor&fiddle/3ndt

Ext.application({
    name: 'Fiddle',

    launch: function () {
        Ext.define('MyViewModel', {
            extend: 'Ext.app.ViewModel',
            alias: 'viewmodel.myviewmodel',

            data: {
                items: ['Item 1', 'Item 2', 'Item 3']
            },
            stores: {
                store: {
                    fields: ['item'],
                    data: []
                }
            },
            formulas: {
                itemCount: {
                    bind: {
                        bindTo: '{items}',
                        deep: true
                    },
                    get: function (data) {
                        //console.log(data);
                        return data.length;
                    }
                },

            }
        });

        Ext.create('Ext.panel.Panel', {
            viewModel: {
                type: 'myviewmodel'
            },

            items: [{
                xtype: 'displayfield',
                fieldLabel: 'Item Count',
                bind: '{itemCount}'
                //bind: '{store.count}'
            }, {
                xtype: 'button',
                text: 'Add item',
                style: 'margin-right: 10px;',
                handler: function () {
                    //console.log('Button 1 clicked');
                    //debugger;
                    let vm = this.up('panel').getViewModel();
                    let stack = vm.get('items');
                    //debugger;
                    stack.push('Item 4');
                    console.log(stack);

                    let store = vm.getStore('store');
                    store.add({
                        item: 'Item'
                    });
                    console.log(store.data.items);
                }
            }],

            renderTo: Ext.getBody()
        });

    }
});


The formula itemCount is deep bound to the array and it returns the number of items in the array. When I click on the Add Item button, I add an item in the array, however the itemCount formula is not re-evaluated.

Any idea why this limitation? I find it surprising.

As workaround, if I use a store and bind to the store.count property, then it works. Comment out bind: '{itemCount}' and remove the comment from the line below, run the fiddle and click the Add Item button a few times.

Just a side note, I created this Vue playground and you can see that vue binds the array properly, i.e. if items are added to the array, then the length of the array is re-evaluated.

App.vue

<script setup>
import { ref } from 'vue'

const msg = ref('Hello World!')
const array = ref(['item 1', 'item 2', 'item 3'])
</script>

<template>
  <h1>{{ msg }}</h1>
  <input v-model="msg">
  <br/>
  <button @click="array.push('Item 4')">
    Click me
  </button>
  <span> Array: {{array}}, length: {{array.length}}</span>
</template>
boggy
  • 3,674
  • 3
  • 33
  • 56
  • I'm afraid it wont't work that way. `items` is a normal JavaScript array, and Ext JS view models will not be notified when the length of this changes. The reason you see it working with the store is because it's "controlled" by Ext JS so it does take care that the `count` property is published to the view model. – Peter Koltai Apr 18 '23 at 11:45
  • It is far from being optimal but you can replace the entire array in the view model each time it is modified (push, remove etc.). This way you don't even need the deep binding. If you find that useful I can share an example code. – Peter Koltai Apr 18 '23 at 11:47
  • @PeterKoltai Thank you - sure, I would like to see the example! – boggy Apr 18 '23 at 16:47

1 Answers1

1

Try this code, just copy to your fiddle. It is not a perfect solution because it creates a new array each time.

Ext.application({
    name: 'Fiddle',
    launch: function () {
        Ext.define('MyViewModel', {
            extend: 'Ext.app.ViewModel',
            alias: 'viewmodel.myviewmodel',
            data: {
                items: ['Item1', 'Item2', 'Item3']
            },
            formulas: {
                itemCount: {
                    bind: '{items.length}',
                    get: function (data) {
                        console.log('Items length is now ' + data);
                        return data;
                    }
                }
            }
        });
        Ext.create('Ext.panel.Panel', {
            viewModel: {
                type: 'myviewmodel'
            },
            items: [{
                xtype: 'displayfield',
                fieldLabel: 'Item Count',
                bind:  '{itemCount}',
            }, {
                xtype: 'button',
                text: 'Add item',
                style: 'margin-right: 10px;',
                handler: function () {
                    let vm = this.up('panel').getViewModel();
                    let stack = vm.get('items');
                    let newStack = Ext.Array.clone(stack);
                    newStack.push('Item ' + stack.length);
                    vm.set('items', newStack);
                }
            }],
            renderTo: Ext.getBody()
        });

    }
});
Peter Koltai
  • 8,296
  • 2
  • 10
  • 20