
# Row merge grouping

When grouping rows, grouped column cells are displayed as merge cells.

#### Row merge grouping

If the RowGroup.mergeMode property is set to true, grouped column cells are displayed as merge cells when grouping rows.

```js
const fields = [
  { fieldName: 'KorName', dataType: 'text' },
  { fieldName: 'Gender', dataType: 'text' },
  { fieldName: 'Age', dataType: 'number' },
  { fieldName: 'Phone', dataType: 'text' },
  { fieldName: 'ProductId', dataType: 'text' },
  { fieldName: 'KorCountry', dataType: 'text' },
  { fieldName: 'OrderDate', dataType: 'datetime', datetimeFormat: 'yyyy-MM-dd', amText: 'AM', pmText: 'PM' },
  { fieldName: 'CardNumber', dataType: 'text' },
  { fieldName: 'Monetary', dataType: 'text' },
  { fieldName: 'StartDate', dataType: 'datetime', datetimeFormat: 'yyyy-MM-dd', amText: 'AM', pmText: 'PM' },
  { fieldName: 'EndDate', dataType: 'datetime', datetimeFormat: 'yyyy-MM-dd', amText: 'AM', pmText: 'PM' },
  { fieldName: 'ToMonth', dataType: 'number' },
  { fieldName: 'Month', dataType: 'number' },
  { fieldName: 'Year', dataType: 'number' },
  { fieldName: 'InterestRate', dataType: 'number' },
  { fieldName: 'SaveCost', dataType: 'number' },
  { fieldName: 'SaveMaturity', dataType: 'number' },
  { fieldName: 'CurrentSave', dataType: 'number' }
];

const columns = [
  { name: 'KorCountry', fieldName: 'KorCountry', width: '100', header: { text: 'Country' } },
  { name: 'Monetary', fieldName: 'Monetary', width: '50', header: { text: 'Monetary' } },
  { name: 'KorName', fieldName: 'KorName', width: '60', header: { text: 'Name' }, checkded: 'true' },
  { name: 'Gender', fieldName: 'Gender', width: '40', header: { text: 'Gender' } },
  { name: 'Age', fieldName: 'Age', width: '40', header: { text: 'Age' }, styleName: 'right-column' },
  { name: 'StartDate', fieldName: 'StartDate', width: '100', header: { text: 'Start Date' } },
  { name: 'EndDate', fieldName: 'EndDate', width: '100', header: { text: 'End Date' } },
  { name: 'ToMonth', fieldName: 'ToMonth', width: '50', header: { text: 'Pay Cnt.' }, styleName: 'right-column' },
  { name: 'Month', fieldName: 'Month', width: '50', header: { text: 'Residuum' }, styleName: 'right-column' },
  { name: 'InterestRate', fieldName: 'InterestRate', width: '50', numberFormat: '0.00', header: { text: 'Interest Rate' }, groupFooter: { text: 'Subtotal: ' }, footer: { text: 'Total: ' }, styleName: 'right-column' },
  { name: 'SaveCost', fieldName: 'SaveCost', width: '80', numberFormat: '#,##0', header: { text: 'Payment' }, groupFooter: { numberFormat: '#,##0', expression: 'sum' }, footer: { numberFormat: '#,##0', expression: 'sum' }, styleName: 'right-column' },
  { name: 'SaveMaturity', fieldName: 'SaveMaturity', width: '80', numberFormat: '#,##0', header: { text: 'Save Maturity' }, groupFooter: { numberFormat: '#,##0', expression: 'sum' }, footer: { numberFormat: '#,##0', expression: 'sum' }, styleName: 'right-column' },
  { name: 'CurrentSave', fieldName: 'CurrentSave', width: '80', numberFormat: '#,##0', header: { text: 'Currency Save' }, groupFooter: { numberFormat: '#,##0', expression: 'sum' }, footer: { numberFormat: '#,##0', expression: 'sum' }, styleName: 'right-column' }
];

RealGrid.setLocale('en');

const { gridView, dataProvider } = RealGrid.createGrid('realgrid', {
  columns,
  header: {
    height: 40
  },
  display: {
    rowHeight: 36,
    emptyMessage: 'There is no data to display.'
  },
  edit: {
    insertable: true,
    appendable: true
  },
  footer: {
    height: 40
  },
  stateBar: {
    width: 16
  },
  groupPanel: {
    visible: true
  },
  onInitialized: (grid) => {
    fetch('/data/en/en/rowGroupData.json')
      .then(response => response.json())
      .then(data => {
        grid.getDataSource().setRows(data);
        grid.groupBy(['KorCountry']);
        grid.setRowGroup({
          mergeMode: true,
          expandedAdornments: 'footer',
          collapsedAdornments: 'footer'
        });
      });
  }
}, {
  fields
});

window.gridView = gridView;
window.dataProvider = dataProvider;

function expandedAdornmentsChange(val) {
  gridView.setRowGroup({
    expandedAdornments: val
  });
}

function collapsedAdornmentsChange(val) {
  gridView.setRowGroup({
    collapsedAdornments: val
  });
}

function expanderChange(val) {
  gridView.setRowGroup({ mergeExpanderVisibility: val });
}
```

```js
gridView.setRowGroup({ mergeMode: true });
```

Like [Row Grouping](/guides/row-group/row-grouping#main-content), you can display it by adding a Header or Footer to each group.
  Likewise, the text to display in the group header can be specified with the `rowGroup.headerStatement` property, and the value to display in each footer cell can be specified with `Column.groupFooter.expression`.

#### RowGroup settings

The [setRowGroup()](/refs/Class/GridView#setrowgroup) function sets information related to the grid RowGroup.

When in the rowGrouping state, you can set the display method of the group footer and group header depending on the expanded or collapsed state of the group.

**When children are being ‘marked’**

```js
gridView.setRowGroup({
   expandedAdornments: $(':radio[name="expanded"]:checked').val()
});
```

_When children are in a ‘hidden state’_

```js
gridView.setRowGroup({
   collapsedAdornments: $(':radio[name="collapsed"]:checked').val()
});
```

_Expander display_

```js
gridView.setRowGroup({
   mergeExpander: $(':radio[name="expander"]:checked').val()
});
```

#### Limitations

Restrictions in merge mode are as follows.

- Grouped columns are placed in order at the front of the grid.
- The position of grouped columns cannot be changed.

#### Show some group footers

When MergedRowGroup, you can use the createFooterCallback property to set the footer to be displayed only for some groups.

```js
const fields = [
  { fieldName: 'KorName', dataType: 'text' },
  { fieldName: 'Gender', dataType: 'text' },
  { fieldName: 'Age', dataType: 'number' },
  { fieldName: 'Phone', dataType: 'text' },
  { fieldName: 'ProductId', dataType: 'text' },
  { fieldName: 'KorCountry', dataType: 'text' },
  { fieldName: 'OrderDate', dataType: 'datetime', datetimeFormat: 'yyyy-MM-dd', amText: 'AM', pmText: 'PM' },
  { fieldName: 'CardNumber', dataType: 'text' },
  { fieldName: 'Monetary', dataType: 'text' },
  { fieldName: 'StartDate', dataType: 'datetime', datetimeFormat: 'yyyy-MM-dd', amText: 'AM', pmText: 'PM' },
  { fieldName: 'EndDate', dataType: 'datetime', datetimeFormat: 'yyyy-MM-dd', amText: 'AM', pmText: 'PM' },
  { fieldName: 'ToMonth', dataType: 'number' },
  { fieldName: 'Month', dataType: 'number' },
  { fieldName: 'Year', dataType: 'number' },
  { fieldName: 'InterestRate', dataType: 'number' },
  { fieldName: 'SaveCost', dataType: 'number' },
  { fieldName: 'SaveMaturity', dataType: 'number' },
  { fieldName: 'CurrentSave', dataType: 'number' }
];

const columns = [
  { name: 'KorCountry', fieldName: 'KorCountry', width: '100', header: { text: 'Country' } },
  { name: 'Monetary', fieldName: 'Monetary', width: '50', header: { text: 'Monetary' } },
  { name: 'KorName', fieldName: 'KorName', width: '60', header: { text: 'Name' }, checkded: 'true' },
  { name: 'Gender', fieldName: 'Gender', width: '40', header: { text: 'Gender' } },
  { name: 'Age', fieldName: 'Age', width: '40', header: { text: 'Age' }, styleName: 'right-column' },
  { name: 'StartDate', fieldName: 'StartDate', width: '100', header: { text: 'Start Date' } },
  { name: 'EndDate', fieldName: 'EndDate', width: '100', header: { text: 'End Date' } },
  { name: 'ToMonth', fieldName: 'ToMonth', width: '50', header: { text: 'Pay Cnt.' }, styleName: 'right-column' },
  { name: 'Month', fieldName: 'Month', width: '50', header: { text: 'Residuum' }, styleName: 'right-column' },
  { name: 'InterestRate', fieldName: 'InterestRate', width: '50', numberFormat: '0.00', header: { text: 'Interest Rate' }, groupFooter: { text: 'Subtotal: ' }, footer: { text: 'Total: ' }, styleName: 'right-column' },
  { name: 'SaveCost', fieldName: 'SaveCost', width: '80', numberFormat: '#,##0', header: { text: 'Payment' }, groupFooter: { numberFormat: '#,##0', expression: 'sum' }, footer: { numberFormat: '#,##0', expression: 'sum' }, styleName: 'right-column' },
  { name: 'SaveMaturity', fieldName: 'SaveMaturity', width: '80', numberFormat: '#,##0', header: { text: 'Save Maturity' }, groupFooter: { numberFormat: '#,##0', expression: 'sum' }, footer: { numberFormat: '#,##0', expression: 'sum' }, styleName: 'right-column' },
  { name: 'CurrentSave', fieldName: 'CurrentSave', width: '80', numberFormat: '#,##0', header: { text: 'Currency Save' }, groupFooter: { numberFormat: '#,##0', expression: 'sum' }, footer: { numberFormat: '#,##0', expression: 'sum' }, styleName: 'right-column' }
];

RealGrid.setLocale('en');

const { gridView, dataProvider } = RealGrid.createGrid('realgrid', {
  columns,
  header: {
    height: 40
  },
  display: {
    rowHeight: 36,
    emptyMessage: 'There is no data to display.'
  },
  edit: {
    insertable: true,
    appendable: true
  },
  footer: {
    height: 40
  },
  stateBar: {
    width: 16
  },
  groupPanel: {
    visible: true
  },
  onInitialized: (grid) => {
    fetch('/data/en/en/rowGroupData.json')
      .then(response => response.json())
      .then(data => {
        grid.getDataSource().setRows(data);
      });
  }
}, {
  fields
});

window.gridView = gridView;
window.dataProvider = dataProvider;

function btnCreateFooterCallback() {
  gridView.setRowGroup({
    mergeMode: true,
    createFooterCallback: function(grid, group) {
      if (group.level >= 3) {
        return false;
      }
      return true;
    }
  });
}
```

```js
gridView.setRowGroup({
     mergeMode: true;
     createFooterCallback: function(grid, group) {
       if (group.level >= 3) {
         return false;
       }
       return true;
     }
   });
```

Show entire group footer

<img src='/images/mergedRowGroup1.png' alt='Show entire group footer'/>

Apply group footer hiding for level 3 and above
<img src='/images/mergedRowGroup2.png' alt='Hide group footer above level 3' />

#### Group footer multi-line output

You can display the group footer in multiple rows or dynamically display only the group footer at a specific level to be displayed in multiple rows.

This is a demo that does not output group footers of level 2 or higher if the footerIndex is 1 or higher.

```js
const fields = [
  { fieldName: 'KorName', dataType: 'text' },
  { fieldName: 'Gender', dataType: 'text' },
  { fieldName: 'Age', dataType: 'number' },
  { fieldName: 'Phone', dataType: 'text' },
  { fieldName: 'ProductId', dataType: 'text' },
  { fieldName: 'KorCountry', dataType: 'text' },
  { fieldName: 'OrderDate', dataType: 'datetime', datetimeFormat: 'yyyy-MM-dd', amText: 'AM', pmText: 'PM' },
  { fieldName: 'CardNumber', dataType: 'text' },
  { fieldName: 'Monetary', dataType: 'text' },
  { fieldName: 'StartDate', dataType: 'datetime', datetimeFormat: 'yyyy-MM-dd', amText: 'AM', pmText: 'PM' },
  { fieldName: 'EndDate', dataType: 'datetime', datetimeFormat: 'yyyy-MM-dd', amText: 'AM', pmText: 'PM' },
  { fieldName: 'ToMonth', dataType: 'number' },
  { fieldName: 'Month', dataType: 'number' },
  { fieldName: 'Year', dataType: 'number' },
  { fieldName: 'InterestRate', dataType: 'number' },
  { fieldName: 'SaveCost', dataType: 'number' },
  { fieldName: 'SaveMaturity', dataType: 'number' },
  { fieldName: 'CurrentSave', dataType: 'number' }
];

const columns = [
  { name: 'KorCountry', fieldName: 'KorCountry', width: '100', header: { text: 'KorCountry' } },
  { name: 'Monetary', fieldName: 'Monetary', width: '100', header: { text: 'Monetary' }, groupFooter: [{ text: 'footerIndex: 0' }, { text: 'footerIndex: 1' }] },
  { name: 'KorName', fieldName: 'KorName', width: '60', header: { text: 'KorName' }, checkded: 'true' },
  { name: 'Gender', fieldName: 'Gender', width: '100', header: { text: 'Gender' }, groupFooter: [{ text: 'footerIndex: 0' }, { text: 'footerIndex: 1' }] },
  { name: 'Age', fieldName: 'Age', width: '40', header: { text: 'Age' }, styleName: 'right-column' },
  { name: 'StartDate', fieldName: 'StartDate', width: '100', header: { text: 'StartDate' } },
  { name: 'EndDate', fieldName: 'EndDate', width: '100', header: { text: 'EndDate' } },
  { name: 'ToMonth', fieldName: 'ToMonth', width: '50', header: { text: 'ToMonth' }, styleName: 'right-column' },
  { name: 'Month', fieldName: 'Month', width: '50', header: { text: 'Month' }, styleName: 'right-column' },
  { name: 'InterestRate', fieldName: 'InterestRate', width: '50', numberFormat: '0.00', header: { text: 'InterestRate' }, groupFooter: [{ text: 'subtotal : ' }, { text: 'subtotal : ' }], footer: { text: 'total : ' }, styleName: 'right-column' },
  { name: 'SaveCost', fieldName: 'SaveCost', width: '80', numberFormat: '#,##0', header: { text: 'SaveCost' }, groupFooter: [{ numberFormat: '#,##0', expression: 'sum' }, { numberFormat: '#,##0', expression: 'sum' }], footer: { numberFormat: '#,##0', expression: 'sum' }, styleName: 'right-column' },
  { name: 'SaveMaturity', fieldName: 'SaveMaturity', width: '80', numberFormat: '#,##0', header: { text: 'SaveMaturity' }, groupFooter: [{ numberFormat: '#,##0', expression: 'sum' }, { numberFormat: '#,##0', expression: 'sum' }], footer: { numberFormat: '#,##0', expression: 'sum' }, styleName: 'right-column' },
  { name: 'CurrentSave', fieldName: 'CurrentSave', width: '80', numberFormat: '#,##0', header: { text: 'CurrentSave' }, groupFooter: [{ numberFormat: '#,##0', expression: 'sum' }, { numberFormat: '#,##0', expression: 'sum' }], footer: { numberFormat: '#,##0', expression: 'sum' }, styleName: 'right-column' }
];

const { gridView, dataProvider } = RealGrid.createGrid('realgrid', {
  columns,
  header: {
    height: 40
  },
  display: {
    rowHeight: 36,
    emptyMessage: 'No data to display.'
  },
  edit: {
    insertable: true,
    appendable: true
  },
  footer: {
    height: 40
  },
  stateBar: {
    width: 16
  },
  groupPanel: {
    visible: true
  },
  onInitialized: (grid) => {
    fetch('/data/en/en/rowGroupData.json')
      .then(response => response.json())
      .then(data => {
        grid.getDataSource().setRows(data);
        grid.groupBy(['KorName', 'Gender', 'Monetary']);
        grid.rowGroup.setFooters([{}, {}]);
        grid.setRowGroup({
          mergeMode: true,
          expandedAdornments: 'footer',
          createFooterCallback: function(grid, group, footerIndex) {
            if (group.level >= 4) {
              return false;
            } else if ((group.level >= 2) && footerIndex > 0) {
              return false;
            }
            return true;
          }
        });
      });
  }
}, {
  fields
});

window.gridView = gridView;
window.dataProvider = dataProvider;
```