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> 
3
  • 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. Commented Apr 18, 2023 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. Commented Apr 18, 2023 at 11:47
  • @PeterKoltai Thank you - sure, I would like to see the example! Commented Apr 18, 2023 at 16:47

1 Answer 1

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() }); } }); 
Sign up to request clarification or add additional context in comments.

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.