Search code examples
extjsgridmetadatarenderer

How to merge cells in an extjs grid panel?


I have extjs grid.Panel and I am trying to mimic cell merging in the rows when there is duplicate data in the first column of consecutive rows. Using a column renderer, I clear a row's first column value if it is a duplicate of a previous row's value. I would like to modify the previous row's first cell's tdAttr to row span the appropriate number of rows. I cannot figure out how to get to a previous row's metaData. Below is my current renderer code.

                  renderer: function(value, metaData, record, row, col, store, gridView){                    
                     
                     var dataIndex = metaData.column.dataIndex;
                     var overrideValue = value;

                     // check previous rows and determine whether this row's first column has the same
                     // value as a previous row's first column
                     if (col == 0){
                        var i = row-1;
                        while (i >= 0 && overrideValue != ""){
                           if (store.data.items[i].get(dataIndex) == value){
                              overrideValue = "";
                              // ----- here i want to update record i's metaData...
                              // metaData.tdAttr = 'rowspan=' + row-i+1
                           } 
                           i--;     
                        }
                     }

                     return overrideValue;
                  }

I've tried a number of ways to get at the metaData associated with a record but have been unsuccessful. The getnodes and getnode methods of the gridView object return undefined.


Solution

  • I created the following solution. I used a combination of a column renderer and a view listener, specifically "viewready". The grid's row line is set to "false" and I use the column renderer to apply a custom style to replace the row line as appropriate and clear the appropriate cells values. I modify the background color of "merged" cells in the "viewready" listener.

    <style>
    .mywrapcell .x-grid-cell-inner {
       white-space: normal;
       border-top-color: #c6c6c6;
       border-top-width: 1px;
       border-top-style: solid;
    }
    </style>
    
    _addGrid: function() {
    
    
          var myModel = Ext.define('User', {
            extend: 'Ext.data.Model',
            fields: [
                {name: 'col1', type: 'string'},
                {name: 'col2',  type: 'string'},
            ]
           });
       
          var myData = [{col1: 'U2', col2: 'Jan 5'},
                        {col1: 'U2', col2: 'Jan 6'},
                        {col1: 'Crowded House', col2: 'Feb 19'},
                        {col1: 'Jack Johnson', col2: 'Apr 4'},
                        {col1: 'Jack Johnson', col2: 'Apr 5'},
                        {col1: 'Cage the Elephant', col2: 'May 10'},
                        {col1: 'Cage the Elephant', col2: 'May 11'},
                        {col1: 'Blondie', col2: 'Jun 6'},
                        {col1: 'Gorillaz', col2: 'Jun 19'},
                        {col1: 'Gorillaz', col2: 'Jun 20'}];
       
          var mystore = Ext.create('Ext.data.Store', {
             model: myModel,
             data: myData,
             proxy: {
                type: 'memory',
                enablePaging: false
             }
          });
    
          var mygrid = Ext.create('Ext.grid.Panel', {
             store: mystore,
             itemId: 'grid',
             viewConfig:{
                listeners: {
                   viewready: function(view){
    
                      var dataIndex = 'col1';
                      
                      // find the index of the column for row spanning
                      var colindex = view.ownerCt.columns.findIndex((x) => x.dataIndex == dataIndex);
                      
                      if (colindex != -1){
                         var viewrows = view.getNodes();
                         var bgcolor = '#fff';
                          
                         // set all the cells to the                      
                         // same background color
                         for(i=0;i<viewrows.length;i++){
                        viewrows[i].cells[colindex].style.backgroundColor = bgcolor;
                         }
                      }
                }
             },
             enableEditing: false,
             enableBulkEdit: false,
             showRowActionsColumn: false,
             enableRanking: false,
             sortableColumns: false,
             columnLines: true,
             rowLines: false, //row lines handled in renderer
             width: 225,
             columns: [
                   {text: 'Artist',
                    dataIndex: 'col1',
                    flex: 1,
                    renderer: function(value, metaData, record, row, col, store, view){                    
                          
                          var overrideValue = value;
                          
                          // check previous rows and determine whether this row's first column has the same
                          // value as a previous row's first column
                          var i = row-1;
                          
                          while (i >= 0 && overrideValue != ""){
                             if (store.data.items[i].get(metaData.column.dataIndex) == value){
                                overrideValue = '';
                             } 
                             i--;     
                          }
                          
                          if (overrideValue != ""){
                             metaData.tdCls = 'mywrapcell';
                          }
                          return overrideValue;
                    }
                   },
                   {
                      text: 'Show Date',
                      dataIndex: 'col2',
                      tdCls: 'mywrapcell'
                   }
             ],
          });
      
          this.add(mygrid);
         
     }
    

    and the result...