Skip to content

July 13, 2012

9

ExtJs 4: Using multiple fields inside a row editor cell for editing large values

by Joe Kuan

[For an update version of this post, check here]

Suppose we have a grid panel with store object holding very large values. We can use column’s renderer to format the large value into readable form. However, when it comes to editing the real value, it is cumbersome to modify with a string of digits. Especially, for applications only require 2 to 3 significant figures accuracy. In another word, we can easily display the value of ‘1.23 B’ or ‘1.23 bil’ instead of 1230000000 but in row editor it reflects the real value behind the store record. Of course, we can use ‘textfield’ and put in some checking and conversion process in between but this may require writing quite a bit of code.

Here is an alternative, we can display two separate edit fields: one number field and one combo box for units inside a row editor cell. In my opinion, this way is neater and more user friendly. Below is a screenshot with ExtJs 4.1 :

Demo

You can see the demo in joekuan.org.

Row Editor Window

We first create a window containing a GridPanel which also includes the RowEditor plugin. Basically, I have created 2 columns for each type of data: one with the combined edit fields and one with the straightforward number field, just for comparing both approaches side by side. In order to put both editing fields into an editor cell, we need to use the new ExtJs 4 container component. Also we need to make sure the width of the column can fit both edit fields.

Here is the code of the GridPanel:

          var win = Ext.create('Ext.window.Window', {
          title: 'Large values example',
          layout: 'fit',
          items: [{
            xtype: 'grid',
            width: 640,
            plugins: [ rowEditing ],
            frame: true,
            store: store,
            columns: [{
               // Column - value
               text: 'Value ($)',
               sortable: true,
               width: 150,
               dataIndex: 'value',
               renderer: formatValue,
               field: {
                  xtype: 'container',
                  layout: 'hbox',
                  flex: 1,
                  items: [{
                    // editor field1 - value number field
                    xtype: 'numberfield',
                    width: 75,
                    id: 'value_numberField',
                    allowBlank: false,
                    allowNegative: false
                    }, {
                    // editor field2 - unit combo box
                    xtype: 'combo',
                    width: 70,
                    id: 'value_combo',
                    valueField: 'value',
                    displayField: 'name',
                    store: valueUnit,
                    mode: 'local',
                    triggerAction: 'all',
                    editable: false
                 }]
              }
             }, {
               // Same column with a normal editor field
               text: 'Value ($)',
               sortable: true,
               width: 150,
               dataIndex: 'value',
               renderer: formatValue,
               field: {
                    xtype: 'numberfield',
               }
            }, {
               text: 'Bandwidth (bps)',
               width: 150,
               sortable: true,
               dataIndex: 'bandwidth',
               renderer: formatBandwidth,
               field: {
                  xtype: 'container',
                  layout: 'hbox',
                  flex: 1,
                  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
                 }]
               }
            }, {
               text: 'Bandwidth (bps)',
               width: 150,
               sortable: true,
               dataIndex: 'bandwidth',
               renderer: formatBandwidth,
               field: {
                  xtype: 'numberfield',
               }
            }]
         }]
        });
    win.show();

The next thing is to populate the content into the sub-editor fields when a row is clicked and the row editor becomes active. To do that, we define the row editor event handler for beforeedit event which is triggered before the row editor is displayed. The beforeedit event handler is called with two parameters: the row editor itself and the edit event object. However, this event handler has a minor bug in version 4.0.7 but it is fixed in the latest 4.1.0, i.e. the record property should be inside the 2nd parameter according to the documentation but it is in the first parameter in version 4.0.7. Here is how the RowEditor plugin is defined:

      var rowEditing = Ext.create('Ext.grid.plugin.RowEditing', {
          listeners: {
             beforeedit: function(editor, e) {
                // Retrieves the row record that the user has clicked on
                // Since version 4.1.0 - it fixes the record property
                var record = (parseInt(Ext.versions.extjs.shortVersion) >= 410) ? e.record : editor.record;
                // Split the actual long value into metric unit and small value
                var lteValUnit = convertValue(record.data.value);
                var gtValUnit = convertBandwidth(record.data.bandwidth);

                // Populate the sub-editor fields
                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]);
             }
          }
      });

The other functions convertValue and convertBandwidth are simply defined as:

      var convertValue = function(value) {
          if (value >= 1000000000000) {
             return [ value / 1000000000000, "T" ];
          } else if (value >= 1000000000) {
             return [ value / 1000000000, "B" ];
          } else if (value >= 1000000) {
             return [ value / 1000000, "M" ];
          } else if (value >= 1000) {
             return [ value / 1000, "k" ];
          }
          return [ value, ' ' ];
      };

      var convertBandwidth = function(value) {
          if (value >= 1000000000) {
             return [ value / 1000000000, "Gbps" ];
          } else if (value >= 1000000) {
             return [ value / 1000000, "Mbps" ];
          } else if (value >= 1000) {
             return [ value / 1000, "kbps" ];
          }
          return [ value, 'bps' ];
      };

Moreover, if you run this example with ExtJS 4.0.7, the row editor doesn’t align properly but again this is fixed in 4.1.0. The following is a screenshot running with 4.0.7:

As you can see, the editor fields inside the row editor are not aligning properly.

Advertisements
9 Comments Post a comment
  1. Lek
    Jan 11 2013

    Nice example, but ‘Update’ doesn’t work.
    It throws an arror saying “Uncaught TypeError: Object [object Object] has no method ‘getValue’ “.
    Any idea on how to tacke that?

    BTW: I think there’s an error in your example;
    your section “// Same column with a normal editor field” actually is the same as the previous column? ;-)

    Reply
    • Joe Kuan
      Jan 11 2013

      It may be that I updated the latest ExtJs version to my website couple weeks ago. I will have a check over the weekend.

      Thanks
      Joe

      Reply
    • Joe Kuan
      Jan 13 2013

      Check the post. I have addressed your issue.

      Joe

      Reply
  2. Valery
    Jul 10 2013

    please, answer, why it does not work at cell editing case?

    Reply
    • Joe Kuan
      Jul 10 2013

      Are you referring to edit INDIVIDUAL cell by double clicking it? If so, I never tried because don’t need that feature.

      Reply
  3. Valery
    Jul 10 2013

    yes, when I try to apply your specified method, but for the occasion celledit plugin. startEdit method is called with exeption of absence some method

    Reply
    • Joe Kuan
      Jul 10 2013

      Sorry, I can’t give you any answer on that as I haven’t tried that before.

      Reply
  4. Gopal
    Oct 3 2013

    not working with Extjs 4.2.1.883, giving error el is not defined for xtype container

    Reply
    • Joe Kuan
      Oct 4 2013

      So sorry. I forgot to update the blog. I have spent a long time trying to fix it and I am still stuck. The chances are that I won’t be able to get it to work in the near future.

      Reply

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: