14/04/2014

ExtJs grid panel column resize to fit data width vs. resize to fit container

It is possible to resize a grid panel column to fit the contents width and it is also possible to resize the grid panel column to fit the size of the grid panel itself. These are two different things and should not be confused.

I will use the setup from my previous post: http://extjs-intro.blogspot.com/2014/04/basic-anatomy.html.You need at least this setup if you are to repeat any of the steps.

For reference, this is the grid panel example code from the ExtJS documentation: http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.grid.Panel.

Let us now increase the width of the panel to 800 pixels to see what happens:



Ext.application({
 name : 'MyApp',
 launch : function () {
 /* Put example code after this line */
  Ext.create('Ext.data.Store', {
   storeId : 'simpsonsStore',
   fields : ['name', 'email', 'phone'],
   data : {
    'items' : [{
      'name' : 'Lisa',
      "email" : "lisa@simpsons.com",
      "phone" : "555-111-1224"
     }, {
      'name' : 'Bart',
      "email" : "bart@simpsons.com",
      "phone" : "555-222-1234"
     }, {
      'name' : 'Homer',
      "email" : "home@simpsons.com",
      "phone" : "555-222-1244"
     }, {
      'name' : 'Marge',
      "email" : "marge@simpsons.com",
      "phone" : "555-222-1254"
     }
    ]
   },
   proxy : {
    type : 'memory',
    reader : {
     type : 'json',
     root : 'items'
    }
   }
  });

  Ext.create('Ext.grid.Panel', {
   title : 'Simpsons',
   store : Ext.data.StoreManager.lookup('simpsonsStore'),
   columns : [{
     text : 'Name',
     dataIndex : 'name'
    }, {
     text : 'Email',
     dataIndex : 'email',
     flex : 1
    }, {
     text : 'Phone',
     dataIndex : 'phone'
    }
   ],
   height : 200,
   width : 800,
   renderTo : Ext.getBody()
  });
 /* Put example code before this line */
 }
});

When we run this in the browser, we will get the following result:
Screenshot 1
The reason why column Email extends to the available space is the following line:
flex : 1

If we are to comment out this line, the screenshot will look like this:
Screenshot 2

Let us now increase the length of one of the names so that the first column is no longer wide enough to show it all. Lets make Lisa of Babylonian descent and rename her to "Lisa Nebuchadnezzar". This should be just long enough not to be shown entirely. And here's the screenshot:
Screenshot 3

Resizing the column to fit the contents can be achieved in the following way. The column will have to be manipulated. The docs we have to be looking at are not those of the grid panel but the columns: http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.grid.column.Column. Scrolling down, there is a method called: autoSize(). According to the description, this should do. We should be calling this method at runtime. To achieve this, we can do the following two operations:
  1. add a property to the column
    autoSizeColumn : true
  2. add the following block to the grid panel
    viewConfig : {
        listeners : {
         refresh : function (dataview) {
          Ext.each(dataview.panel.columns, function (column) {
           if (column.autoSizeColumn === true)
            column.autoSize();
          })
         }
        }
       },
    

The final result can be seen in the last screenshot:
Screenshot 4

For completeness, this is the final code:
Ext.application({
 name : 'MyApp',
 launch : function () {
  /* Put example code after this line */
  Ext.create('Ext.data.Store', {
   storeId : 'simpsonsStore',
   fields : ['name', 'email', 'phone'],
   data : {
    'items' : [{
      'name' : 'Lisa Nebuchadnezzar',
      "email" : "lisa@simpsons.com",
      "phone" : "555-111-1224"
     }, {
      'name' : 'Bart',
      "email" : "bart@simpsons.com",
      "phone" : "555-222-1234"
     }, {
      'name' : 'Homer',
      "email" : "home@simpsons.com",
      "phone" : "555-222-1244"
     }, {
      'name' : 'Marge',
      "email" : "marge@simpsons.com",
      "phone" : "555-222-1254"
     }
    ]
   },
   proxy : {
    type : 'memory',
    reader : {
     type : 'json',
     root : 'items'
    }
   }
  });

  Ext.create('Ext.grid.Panel', {
   title : 'Simpsons',
   store : Ext.data.StoreManager.lookup('simpsonsStore'),
   columns : [{
     text : 'Name',
     dataIndex : 'name',
     autoSizeColumn : true
    }, {
     text : 'Email',
     dataIndex : 'email',
     //flex : 1
    }, {
     text : 'Phone',
     dataIndex : 'phone'
    }
   ],
   height : 200,
   width : 800,
   viewConfig : {
    listeners : {
     refresh : function (dataview) {
      Ext.each(dataview.panel.columns, function (column) {
       if (column.autoSizeColumn === true)
        column.autoSize();
      })
     }
    }
   },
   renderTo : Ext.getBody()
  })
  /* Put example code before this line */
 }
});

References:
http://www.sencha.com/forum/showthread.php?262891-Auto-fit-column-widths-instead-of-having-fix-widths
http://en.wikipedia.org/wiki/Nebuchadnezzar_I
http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.grid.Panel
http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.grid.column.Column
http://docs.sencha.com/extjs/4.2.1/#!/api/Ext

Basic Anatomy

Constraints:
At the time of writing of this and consequent posts, the current open source version of ExtJS is 4.2.1.

Prerequisites:
Screenshot 1
  1. Download ExtJS from: http://www.sencha.com/products/extjs/download/
  2. Extract it into a folder locally (350MB+)
  3. Rename the generated folder to "extjs" (in my case the folder name was too long: "ext-4.2.1.883").
  4. Create index.html and app.js at the same level as the folder extjs (see screenshot on the right).
  5.  

The html page serving an ExtJS application can be as stripped down as the code hereunder:
<!DOCTYPE html>
<html>
<head>
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <title>Test</title>
 <script src="extjs/ext-all-debug.js"></script>
 <script src="extjs/ext-theme-neptune.js"></script>
 <link rel="stylesheet" href="extjs/packages/ext-theme-neptune/build/resources/ext-theme-neptune-all.css">
 <script type="text/javascript" src="app.js"></script>
</head>
<body></body>
</html>

app.js could then have the following stripped down anatomy:
Ext.application({
 name : 'MyApp',
 launch : function () {
 /* Put example code after this line */
  
 /* Put example code before this line */
 }
});

And finally, let us take the grid panel example code (http://docs.sencha.com/extjs/4.2.1/#!/api/Ext.grid.Panel) from the documentation and insert it into the foreseen place holder (it's the same code, formatted for convenience using notepad++):
Ext.application({
 name : 'MyApp',
 launch : function () {
 /* Put example code after this line */
  Ext.create('Ext.data.Store', {
   storeId : 'simpsonsStore',
   fields : ['name', 'email', 'phone'],
   data : {
    'items' : [{
      'name' : 'Lisa',
      "email" : "lisa@simpsons.com",
      "phone" : "555-111-1224"
     }, {
      'name' : 'Bart',
      "email" : "bart@simpsons.com",
      "phone" : "555-222-1234"
     }, {
      'name' : 'Homer',
      "email" : "home@simpsons.com",
      "phone" : "555-222-1244"
     }, {
      'name' : 'Marge',
      "email" : "marge@simpsons.com",
      "phone" : "555-222-1254"
     }
    ]
   },
   proxy : {
    type : 'memory',
    reader : {
     type : 'json',
     root : 'items'
    }
   }
  });

  Ext.create('Ext.grid.Panel', {
   title : 'Simpsons',
   store : Ext.data.StoreManager.lookup('simpsonsStore'),
   columns : [{
     text : 'Name',
     dataIndex : 'name'
    }, {
     text : 'Email',
     dataIndex : 'email',
     flex : 1
    }, {
     text : 'Phone',
     dataIndex : 'phone'
    }
   ],
   height : 200,
   width : 400,
   renderTo : Ext.getBody()
  });
 /* Put example code before this line */
 }
});
Loading index.html would then result in the following screenshot:
Screenshot 2

First Post

I am starting this website in order to catalog my knowledge about ExtJS. I am new to this framework and therefore I will start from the basics working my way into more complex matters.

I am setting this website also because of frustration. I have spent a lot of time looking for the right answers. This process starts with asking the right questions. Forums being forums, when you finally find somebody who has asked the right question, you also find somebody politely explaining how to read the fine manual and pointing back to the sometimes useless documentation which in my case is usually my starting point and gets me nowhere.

This should be enough for a first post. The next one will have some substance.