Guide applies to: classic

Using Components in Grids

Since ExtJS 5.0, developers have had the ability to embed components within grid cells using the Widget Column class.

Beginning in ExtJS 6.2.0, developers have the ability to configure a component to be displayed in an expansion row below (or, configurably, above) the data row using the Row Widget plugin.

In this guide we will cover how to embed components in grid cells, or in an expansion row.

The Widget Column

Widget Column allows you to easily embed any Component into a Grid cell. Adding a Widget Column couldn’t be easier. Simply assign your column an xtype of “widgetcolumn” and specify its widget config. The widget config is an object that contains the xtype to create for each cell. This xtype can refer to any Ext.Widget or Ext.Component class.

Using the Widget Column to add Sparkline widgets to a Grid, you can accomplish an impressive amount of data visualization as you can see below.

Using Components in Grids - 图1

For a live example of the above image, please visit the Widget Grid.

Enough talk, let’s see this thing in action. In the following example, we create a store with a small set of records that populates a Grid with a Widget Column.

The Widget Column contains a Progress Bar widget, which is added to each row.

Expand Code

JS Run

  1. var store = Ext.create('Ext.data.Store', {
  2. fields: ['name','progress'],
  3. data: [
  4. { name: 'Test 1', progress: 0.10 },
  5. { name: 'Test 2', progress: 0.23 },
  6. { name: 'Test 3', progress: 0.86 },
  7. { name: 'Test 4', progress: 0.31 }
  8. ]
  9. });
  10. Ext.create({
  11. xtype: 'grid',
  12. title: 'Widget Column Demo',
  13. store: store,
  14. columns: [{
  15. text: 'Test Number',
  16. dataIndex: 'name',
  17. width: 100
  18. }, {
  19. xtype: 'widgetcolumn',
  20. text: 'Progress',
  21. width: 120,
  22. dataIndex: 'progress',
  23. widget: {
  24. xtype: 'progressbarwidget',
  25. textTpl: '{value:percent}'
  26. }
  27. }],
  28. width: 220,
  29. height: 250,
  30. renderTo: document.body
  31. });

Understanding the “widget” Config

The widget config of a Widget Column is used to define the type of component to embed in the cells. Based on the xtype contained in the widget config, the Widget Column will create, and manage the lifecycle of instances of the required component. This config cannot be an instance already because Widget Column needs one instance per rendered cell.

Each instance is automatically connected with a specific record and row in the Grid. Over the lifetime of the Grid, the Widgets created for a row will be “recycled” and connected to different records and rows.

The field referenced by the column’s dataIndex is bound to the embedded component’s defaultBindProperty.

Since 6.2.0, components embedded in grids have access to the ViewModel and all the data within it. The ViewModel contains two row-specific properties:

  1. record
  2. recordIndex

Row body components.

The Row Widget plugin. allows developers to specify a component to embed in an expansion row in a very similar way to using a Widget Column

To enable this, configure the RowWidget plugin with a widget property:

  1. plugins: [{
  2. ptype: 'rowwidget',
  3. // The widget definition describes a widget to be rendered into the expansion row.
  4. // It has access to the application's ViewModel hierarchy. Its immediate ViewModel
  5. // contains a record and recordIndex property. These, or any property of the record
  6. // (including association stores) may be bound to the widget.
  7. widget: {
  8. xtype: 'form'
  9. ...

The embedded component has access to the grid’s ViewModel, including the record and recordIndex properties.

The grid may be configured with a rowViewModel setting which may specify a type of ViewModel to create which may include custom data and formulas to help provide data for the widgets.

See Row Widget Grid

Using Components in Grids - 图2

What is a Widget?

The Ext.Widget class, or just “widget”, is a lightweight class similar to Component, but consists solely of an Ext.dom.Element and associated listeners. This makes a Widget quite different from a normal Component because the Ext.Widget class does not derive from Ext.Component. Component provides robust life-cycle management, which adds a tremendous amount of functionality. This functionality, however, comes at some cost.

We have provided a few stock Widgets with ExtJS. These include:

  • Progress Bar (Ext.Progress or “progressbarwidget”)
  • Slider (Ext.slider.Widget or “sliderwidget”)
  • Sparklines (Ext.sparkline.*)
    • Line (“sparklineline”)
    • Bar (“sparklinebar”)
    • Discrete (“sparklinediscrete”)
    • Bullet (“sparklinebullet”)
    • Pie (“sparklinepie”)
    • Box (“sparklinebox”)
    • TriState (“sparklinetristate”)

Using Widgets

As with normal Components, Widgets can be added to the items of a Container. For example, we can add a Sparkline to a toolbar:

Expand Code

JS Run

  1. var panel = Ext.create({
  2. xtype: 'panel',
  3. title: 'Title',
  4. frame: true,
  5. renderTo: document.body,
  6. width: 250,
  7. height: 150,
  8. html: 'Some text',
  9. tbar: [{
  10. text: 'Button'
  11. }, '->', {
  12. xtype: 'sparklineline',
  13. fillColor: '#ddf',
  14. width: 100,
  15. height: 20,
  16. values: [2, 3, 0, 4, -1]
  17. }]
  18. });

In the case of Sparklines, you must provide a size (both width and height) or use an ExtJS layout manager to do so. This is because the internal drawings have no natural size.

Custom Widgets

While ExtJS ships with a “widget-ized” version of the Slider and Progressbar as well as the new Sparklines, there will most likely be situations in which you’d like to create your own Widgets. The decision of whether to derive from Ext.Component vs Ext.Widget really comes down to the complexity of the class being created.
Simple componentry can often avoid things like the Component life-cycle and layouts and just map config properties to the associated elements while responding to element events (like ‘click’, ‘dblclick’, ‘mouseover’, etc.).

To create a Widget you extend Ext.Widget and define your element template and its listeners.

  1. Ext.define('MyWidget', {
  2. extend: 'Ext.Widget',
  3. // The element template - passed to Ext.Element.create()
  4. element: {
  5. reference: 'element',
  6. listeners: {
  7. click: 'onClick'
  8. },
  9. children: [{
  10. reference: 'innerElement',
  11. listeners: {
  12. click: 'onInnerClick'
  13. }
  14. }]
  15. },
  16. constructor: function(config) {
  17. // Initializes our element from the template, and calls initConfig().
  18. this.callParent([config]);
  19. // After calling the superclass constructor, the Element is available and
  20. // can safely be manipulated. Reference Elements are instances of
  21. // Ext.Element, and are cached on each Widget instance by reference name.
  22. },
  23. onClick: function() {
  24. // Listeners use this Widget instance as their scope
  25. console.log('element clicked', this);
  26. },
  27. onInnerClick: function() {
  28. // Access the innerElement reference by name
  29. console.log('inner element clicked', this.innerElement);
  30. }
  31. });

This will feel very familiar to those who have written an ExtJS Modern Component. That is because Ext.Widget is an enhanced version of Ext.AbstractComponent from ExtJS Modern. The ability to add listeners to the element template is one of those enhancements, but there are a handful of others. Refer to the documentation on Ext.Widget for more details.