Ext.ux.layout.FillContainer

One of the pages on the Ext JS app I’m currently working on has a form with a grid underneath. The page exists as a tab inside an Ext.TabPanel, and uses the border layout, with the form as the ‘north’ component and the grid as ‘center’.

The trouble with this is that the grid shrinks down to an unusable size when the browser window is too small, ending up like this:

Border layout

We could alternatively use a basic container layout, but this limits us to a fixed height for the grid, meaning we waste space at the bottom:

Container layout

Enter the imaginatively named FillContainer:

new Ext.Panel({
  autoScroll: true,
  layout: 'fillcontainer',
  items : [
    {
      html  : 'Pretend this is a form',
      height: 400
    },
    {
      html         : 'And this is the grid',
      minHeight    : 250,
      fillContainer: true
    }
  ]
});

If our containing panel shrinks to less than 650px in height, the grid will be automatically sized to 250px and a vertical scrollbar will appear on the panel, like this:

Fill Container with scroll bar

If the panel’s height increases to, say, 900px, the grid gets resized to 500px high. This way we use the space when it’s available, while maintaining a usable interface when height is limited:

Fill Container with stretched item

Here’s the code that makes it work:

Ext.ns('Ext.ux.layout');

/**
 * @class Ext.ux.layout.FillContainerLayout
 * @extends Ext.layout.ContainerLayout
 * @author Ed Spencer (http://edspencer.net)
 * Extended version of container layout which expands a given child item to the 
 * full height of the container, honouring the item's minHeight property
 */
Ext.ux.layout.FillContainerLayout = Ext.extend(Ext.layout.ContainerLayout, {
  monitorResize: true,
  
  /**
   * After rendering each item, resize the one with fillContainer == true
   */
  onLayout: function(ct, target) {
    Ext.ux.layout.FillContainerLayout.superclass.onLayout.apply(this, arguments);
    
    var ctHeight    = ct.getHeight(),
        itemsHeight = 0,
        expandItem;
    
    ct.items.each(function(item) {
      if (item.fillContainer === true) {
        expandItem = item;
      } else {
        itemsHeight += item.getHeight();
      }
    });
    
    //set the expand item's height to fill the container
    if (expandItem != undefined && ctHeight > itemsHeight) {
      var newHeight = ctHeight - itemsHeight;
      
      expandItem.setHeight(Math.max(newHeight, expandItem.minHeight));
    }
  }
});

Ext.Container.LAYOUTS['fillcontainer'] = Ext.ux.layout.FillContainerLayout;

As we’re just extending the default container layout, your items will be rendered in the order you specify them. The expanding item doesn’t have to be the last one – we could equally have set fillContainer and minHeight on the form to expand that instead of the grid.

%d bloggers like this: