javascriptextjsextjs3

ExtJS 3.4 change set same value on multiple DisplayFields at once


Working in ExtJS 3.4, I need to show some values on multiple rows (form layout). Each row appears like this:

<label> <field> <unit of measure>

Where <unit of measure> is a DisplayField with a non-manually-editable text indicating a unit of measure (e.g. liters, meters, ...).

I need to add a mechanism to toggle between units of measure, e.g. a button. Ideally, I would like to click this button, change one value (or call only one setter method), and see the new value on the <unit of measure> parts of my interface. In other words, I would like not to have to keep and cycle through a series of references to multiple DisplayField objects.

So far I have tried instantiating and keeping a reference to one DisplayField and insert it in multiple rows, so that I could call field.setValue(...), like this:

var dispF = new Ext.form.DisplayField({
    value:'liters'
});
var row1 = new Ext.form.CompositeField({
    ...
    items: [<some numberfield 1>, dispF]
    ...
});
var row2 = new Ext.form.CompositeField({
    ...
    items: [<some numberfield 2>, dispF]
    ...
});
//Calling this by some means
dispF.setValue('m^3');

However, dispF will only be rendered on the last instantiated element which makes use of it (in this case row2).

I also tried the following:

var t = 'liters';
var dispF = {
    xtype:'displayfield',
    value:t
};
var row1 = new Ext.form.CompositeField({
    ...
    items: [<some numberfield 1>, dispF]
    ...
});
var row2 = new Ext.form.CompositeField({
    ...
    items: [<some numberfield 2>, dispF]
    ...
});
...
//Calling this by some means
t='m^3';

In this case, 'liters' gets rendered to the right position for all rows, but it's not changed to 'm^3'.

I would like not to use a grid for this matter.

Handling each field manually may be a little demanding, as rows are many, and may in fact contain more than one field & unit-of-measure group, while storing them in arrays would make the code harder to read to whoever came after (code readability must be accounted for, here).

Is there a way to update the DisplayField in every row by performing only one operation (e.g. assignment, call to setValue(), ...), rather than declare and instantiate a DisplayField for every row, and then invoke setValue() on each of them?


Solution

  • Next solution may help you. What is different here is that the values are changed with one user-defined function call, not with one operation. But with this solution you don't need to keep a reference for every displayfield object or store them in array.

    Steps in the solution are: create displayfield subclass and user-definded function:

    Ext.onReady(function(){
        // Class definition.
        TestDisplayField = Ext.extend(Ext.form.DisplayField, {
            constructor: function(config) {
                TestDisplayField.superclass.constructor.call(this, config);
            },
        });
        Ext.reg('testdisplayfield', TestDisplayField);
    
        // Global setter function.
        function setTestDisplayFieldValues(container, value, xtype) {
            var items = container.items;
            for (var i = 0; i < items.length; i++) {
                var component = items.get(i);
                if (Ext.isDefined(component.items)) {
                    setTestDisplayFieldValues(component, value, xtype)
                } else {
                    if (component.xtype == xtype) {
                        component.setValue(value);
                    }
                }
            }
        };
    
        // Components. 
        // Here are 'displayfield' and 'tesdisplayfield' components just for test.
        var row1 = new Ext.form.CompositeField({
            items: [
                {xtype: 'numberfield', width: 50}, {xtype: 'displayfield', value : 'liters', width: 100},
                {xtype: 'numberfield', width: 50}, {xtype: 'displayfield', value : 'liters', width: 100},
                {xtype: 'numberfield', width: 50}, {xtype: 'testdisplayfield', value : 'liters', width: 100},
                {xtype: 'numberfield', width: 50}, {xtype: 'testdisplayfield', value : 'liters', width: 100}
            ]
        });
        var row2 = new Ext.form.CompositeField({
            items: [
                {xtype: 'numberfield', width: 50}, {xtype: 'displayfield', value : 'liters', width: 100},
                {xtype: 'numberfield', width: 50}, {xtype: 'displayfield', value : 'liters', width: 100},
                {xtype: 'numberfield', width: 50}, {xtype: 'testdisplayfield', value : 'liters', width: 100},
                {xtype: 'numberfield', width: 50}, {xtype: 'testdisplayfield', value : 'liters', width: 100}
            ]
        }); 
    
        // Form 
        Ext.create(
            {
            xtype: 'form',
            id: 'testform',
            renderTo: Ext.getBody(),
            title: 'Image', 
            width: 600,
            height: 300,
            layout: 'vbox',
            items: [
                row1,
                row2
            ],
            buttons: [
                {
                text: 'Set value',
                handler: function(button) {
                    // Change the values of all 'testdisplayfield' components.
                    // Here you can use 'displayfield' as xtype if all you components are 'displayfield' and must be changed.
                    // In this case it's not necessary to define 'TestDisplayField' class.
                    setTestDisplayFieldValues(Ext.getCmp('testform'), 'm^3', 'testdisplayfield');
                }
                }
            ]
        });
    });
    

    Notes:

    Tested with ExtJS 3.4