Skip to content

January 13, 2013

6

[Updated] ExtJs 4.1.1: Using multiple fields inside a row editor cell for editing large values

by Joe Kuan

Awhile ago, I have written on how to treat a row editor field with multiple form fields. However, the solution wasn’t working nicely (and also quite buggy) with the latest ExtJs 4.1.1. This post shows you a working example with row update.

[ Update: This doesn’t work on Ext 4.2.1. I have spent a significant time to fix it but still having issue. ]

In order to get row editor plugin working, we need to define editor option in the column model from the GridPanel. Since we use a container object for containing multiple form fields instead of normal single form field, we need to define a specific method for the container, getValue, to return the value from underneath field components, (see highlighted line numbers: 151 and 187). The idea behind is to get the container object behaving like a form field which also has getValue method as well as a Container class. In another word, we are trying to do what a ExtJs 3 CompositeField does which is obsolete in ExtJs 4.

As for updating the row from the composite fields, we need to define validateedit event for the row editor plugin; check for any value changes and mark dirty and do an Ajax store update if necessary.

Here is the screenshot showing a row is being modified:
ExtJs container field update

The row has been updated and marked dirty
Container field updated

Example code and demo

The following is the full example code and the online demo has also been updated

Ext.Loader.setConfig({
    enabled : true,
    disableCaching : true, // For debug only
});

Ext.application({
    launch : function() {

        var rowEditing = Ext.create('Ext.grid.plugin.RowEditing', {
            listeners: {
                // Break down the long value in the store into separate fields
                beforeedit: function(editor, e) {
                    // 4.1 fix the parameter
                    var record = (parseInt(Ext.versions.extjs.shortVersion) >= 410) ? e.record : editor.record;
                    var lteValUnit = convertValue(record.data.value);
                    var gtValUnit = convertBandwidth(record.data.bandwidth);
                    Ext.getCmp('value_numberField').setValue(lteValUnit[0]);
                    Ext.getCmp('value_combo').setValue(lteValUnit[1]);
                    Ext.getCmp('bandwidth_numberField').setValue(gtValUnit[0]);
                    Ext.getCmp('bandwidth_combo').setValue(gtValUnit[1]);
                },
                // Manually check between the new and old values and
                // set mark dirty
                validateedit: function(editor, e) {
                    //console.log(e);
                    if (!Ext.isNumeric(e.newValues.value) ||
                        !Ext.isNumeric(e.newValues.bandwidth)) {
                        return false;
                    }
                    if (e.originalValues.value !== e.newValues.value) {
                        e.record.data.value = e.newValues.value;
                        e.record.setDirty(true);
                    }
                    if (e.originalValues.bandwidth !== e.newValues.bandwidth) {
                        e.record.data.bandwidth = e.newValues.bandwidth;
                        e.record.setDirty(true);
                    }
                    // Optional: here you can set the Ajax update for the store
                    // if the record is dirty
                    return true;
                }
            }
        });

        var convertValue = function(value) {
            if (value >= 1000000000000) {
                return [ value / 1000000000000, 1000000000000 ];
            } else if (value >= 1000000000) {
                return [ value / 1000000000, 1000000000];
            } else if (value >= 1000000) {
                return [ value / 1000000, 1000000 ];
            } else if (value >= 1000) {
                return [ value / 1000, 1000 ];
            }
            return [ value, 1 ];
        };

        var convertBandwidth = function(value) {
            if (value >= 1000000000) {
                return [ value / 1000000000, 1000000000 ];
            } else if (value >= 1000000) {
                return [ value / 1000000, 1000000 ];
            } else if (value >= 1000) {
                return [ value / 1000, 1000 ];
            }
            return [ value, 1 ];
        };

        var store = Ext.create("Ext.data.Store", {
            autoDestroy: false,
            proxy: {
                type: 'memory'
            },
            fields: [ 'value', 'bandwidth' ],
            data: [ { value: 123000000000000,  bandwidth: 12300000000000 } ,
                    { value: 2240000000, bandwidth: 2240000000 },
                    { value: 11330000, bandwidth: 1130000 },
                    { value: 9800, bandwidth: 987 },
                    { value: 886, bandwidth: 0 } ]
        });

        var valueUnit = Ext.create("Ext.data.ArrayStore", {
            autoDestroy: true,
            fields: [ 'name', 'value' ],
            data: [ [ 'T', 1000000000000 ],
                    [ 'B', 1000000000 ],
                    [ 'M', 1000000 ],
                    [ 'k', 1000 ],
                    [ ' ', 1 ]
                  ]
        });

        var bandwidthUnit = Ext.create("Ext.data.ArrayStore", {
            autoDestroy: true,
            fields: [ 'name', 'value' ],
            data: [ [ 'Gbps', 1000000000 ],
                    [ 'Mbps', 1000000 ],
                    [ 'kbps', 1000 ],
                    [ 'bps', 1 ]
                  ]
        });

        var formatValue = function(value) {
            if (value >= 1000000000000) {
                return (value / 1000000000000).toFixed(2) + " T";
            } else if (value >= 1000000000) {
                return (value / 1000000000).toFixed(2) + " B";
            } else if (value >= 1000000) {
                return (value / 1000000).toFixed(2) + " M";
            } else if (value >= 1000) {
                return (value / 1000).toFixed(2) + " k";
            }

            return value;
        };

        var formatBandwidth = function(value) {
            if (value >= 1000000000) {
                return (value / 1000000000).toFixed(2) + " Gbps";
            } else if (value >= 1000000) {
                return (value / 1000000).toFixed(2) + " Mbps";
            } else if (value >= 1000) {
                return (value / 1000).toFixed(2) + " kbps";
            }

            return value + " bps";
        };

        var win = Ext.create('Ext.window.Window', {
            title: 'Large values example (ExtJs ' +
                   Ext.versions.extjs.version + ')',
            layout: 'fit',
            items: [{
                xtype: 'grid',
                width: 400,
                plugins: [ rowEditing ],
                frame: true,
                store: store,
                columns: [{
                    text: 'Value ($)',
                    sortable: true,
                    width: 150,
                    dataIndex: 'value',
                    renderer: formatValue,
                    editor: {
                        xtype: 'container',
                        layout: 'hbox',
                        flex: 1,
                        // This getValue is called by the roweditor plugin
                        // we provide it to emulate as a field getValue
                        getValue: function() {
                            // Combine both fields to a single value
                            var val = Ext.getCmp('value_numberField').getValue();
                            var unit = Ext.getCmp('value_combo').getValue();
                            return val * unit;
                        },
                        items: [{
                            xtype: 'numberfield',
                            width: 75,
                            id: 'value_numberField',
                            allowBlank: false,
                            allowNegative: false
                        }, {
                            xtype: 'combo',
                            width: 70,
                            id: 'value_combo',
                            valueField: 'value',
                            displayField: 'name',
                            store: valueUnit,
                            mode: 'local',
                            triggerAction: 'all',
                            editable: false
                        }]
                    }
                }, {
                    text: 'Bandwidth (bps)',
                    width: 150,
                    sortable: true,
                    dataIndex: 'bandwidth',
                    renderer: formatBandwidth,
                    editor: {
                        xtype: 'container',
                        layout: 'hbox',
                        flex: 1,
                        // This getValue is called by the roweditor plugin
                        // we provide it to emulate as a field getValue
                        getValue: function() {
                            // Combine both fields to a single value
                            var val =
                                Ext.getCmp('bandwidth_numberField').getValue();
                            var unit =
                                Ext.getCmp('bandwidth_combo').getValue();
                            return val * unit;
                        },
                        items: [{
                            xtype: 'numberfield',
                            width: 75,
                            id: 'bandwidth_numberField',
                            allowBlank: false,
                            allowNegative: false
                        }, {
                            xtype: 'combo',
                            width: 70,
                            id: 'bandwidth_combo',
                            valueField: 'value',
                            displayField: 'name',
                            store: bandwidthUnit,
                            mode: 'local',
                            triggerAction: 'all',
                            editable: false
                        }]
                    }
                }]
            }]
        });
        win.show();
    }
});

6 Comments Post a comment
  1. Jens H.
    May 28 2013

    Sadly this gives a fatal error on ExtJs 4.2. It seems no other elements other than Formfields are allowed in the “editor” property now. We did things like the above a lot in our application, and now it’s all broken.

    Do you have an idea how to fix this? Thanks!

    Reply
    • Joe Kuan
      Jun 3 2013

      Sorry for the late reply. Ooops, didn’t realise this doesn’t work anymore. I have too many stuff on the internet that I have no time to check.

      I try to dig some free time later this week and have a look.

      Thanks
      Joe

      Reply
    • Joe Kuan
      Jun 6 2013

      I have fixed the demo. For the source, check my new post. Thanks.

      Reply
  2. Alexei P
    Nov 13 2013

    Thank you for a hint how to customize row editing plugin. Could you please suggest technique to customize row editing so it will layout editing cells in two rows. For example JanuaryComment field under JanuaryValue

    Reply
    • Joe Kuan
      Nov 16 2013

      Hi, I won’t recommend to use my example because the internal structure of row editor has changed since 4.2. The change breaks the demo and I have spent a long time trying to fix it but no success.

      Reply
      • Alexei P
        Nov 16 2013

        After play a bit with your example I’ve realize that I asked too much. “It’s against cell editor nature to edit more than one cell”.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Note: HTML is allowed. Your email address will never be published.

Subscribe to comments

%d bloggers like this: