Grid Мulti-cell Selection and Row Selection

Multi-cell selection enables range data selection in the Grid. Variety of multi-cell selection capabilities are available:

  • By Mouse drag - Rectangular data selectoion of cells would be performed.
  • By Ctrl key press + Mouse drag - Multiple range selections would be performed. Any other existing cell selection will be persisted.
  • Instant multi-cell selection by using Shift key. Select single cell and select another single cell by holding the Shift key. Cell range between the two cells will be selected. Keep in mind that if another second cell is selected while holding Shift key the cell selection range will be updated based on the first selected cell position (starting point).
  • Keyboard multi-cell selection by using the Arrow keys while holding Shift key. Multi-cell selection range will be created based on the focused cell.
  • Keyboard multi-cell selection by using the Ctrl + Arrow keys and Ctrl + Home/End while holding Shift key. Multi-cell selection range will be created based on the focused cell.
  • Clicking with the Left Mouse key while holding Ctrl key will add single cell ranges into the selected cells collection.
  • Continuous multiple cell selection is available, by clicking with the mouse and dragging.

Demo

Keyboard navigation interactions

While Shift key is pressed
  • Shift + Arrow Up to add above cell to the current selection.
  • Shift + Arrow Down to add below cell to the current selection.
  • Shift + Arrow Left to add left cell to the current selection.
  • Shift + Arrow Right to add right cell to the current selection.
While Ctrl + Shift keys are pressed
  • Ctrl + Shift + Arrow Up to select all cells above the focused cell in the column.
  • Ctrl + Shift + Arrow Down to select all cells below the focused cell in the column.
  • Ctrl + Shift + Arrow Left to select all cells till the start of the row.
  • Ctrl + Shift + Arrow Right to select all cells till the end of the row.
  • Ctrl + Shift + Home to select all cells from the focused cell till the first-most cell in the grid
  • Ctrl + Shift + End to select all cells from the focused cell till the last-most cell in the grid
Note

Continuous scroll is possible only within Grid's body.

Api usage

Below are the methods that you can use in order to select ranges, clear selection or get selected cells data.

Select range

selectRange(range) - Select a range of cells with the API. rowStart and rowEnd should use row indexes and columnStart and columnEnd could use column index or column data field value.

const range = { rowStart: 2, rowEnd: 2, columnStart: 1, columnEnd: 1 };
this.grid1.selectRange(range);
...

const range = { rowStart: 0, rowEnd: 2, columnStart: 'Name', columnEnd: 'ParentID' };
this.grid1.selectRange(range);
Note

Select range is additive operation. It will not clear your previous selection.

Clear cell selection

clearCellSelection() will clear the current cell selection.

Get selected data

getSelectedData() will return array of the selected data in format depending on the selection. Examples below:

  1. If three different single cells are selected:

    expectedData = [
     { CompanyName: "Infragistics" },
     { Name: "Michael Langdon" },
     { ParentID: 147 }
    ];
    
  2. If three cells from one column are selected:

    expectedData = [
     { Address: "Obere Str. 57"},
     { Address: "Avda. de la Constitución 2222"},
     { Address: "Mataderos 2312"}
    ];
    
  3. If three cells are selected with mouse drag from one row and three columns:

    expectedData = [
     { Address: "Avda. de la Constitución 2222", City: "México D.F.", ContactTitle: "Owner" }
    ];
    
  4. If three cells are selected with mouse drag from two rows and three columns:

    expectedData = [
     { ContactTitle: "Sales Agent", Address: "Cerrito 333", City: "Buenos Aires"},
     { ContactTitle: "Marketing Manager", Address: "Sierras de Granada 9993", City: "México D.F."}
    ];
    
  5. If two different ranges are selected:

    expectedData = [
     { ContactName: "Martín Sommer", ContactTitle: "Owner"},
     { ContactName: "Laurence Lebihan", ContactTitle: "Owner"},
     { Address: "23 Tsawassen Blvd.", City: "Tsawassen"},
     { Address: "Fauntleroy Circus", City: "London"}
    ];
    
  6. If two overlapping ranges are selected, the format would be:

    expectedData = [
     { ContactName: "Diego Roel", ContactTitle: "Accounting Manager", Address: "C/ Moralzarzal, 86"},
     { ContactName: "Martine Rancé", ContactTitle: "Assistant Sales Agent", Address: "184, chaussée de Tournai", City: "Lille"},
     { ContactName: "Maria Larsson", ContactTitle: "Owner", Address: "Åkergatan 24", City: "Bräcke"},
     { ContactTitle: "Marketing Manager", Address: "Berliner Platz 43", City: "München"}
    ];
    
Note

selectedCells() will not return any result if the cell is not visible in grids view port, although getSelectedData() will return the selected cell data. getSelectedRanges(): GridSelectionRange[] will return the current selected ranges in the grid from both keyboard and pointer interactions. The type is GridSelectionRange[].

Features integration

The multi-cell selection is index based (DOM elements selection).

  • Sorting - When sorting is performed selection will not be cleared. It will leave currently selected cells the same while sorting ascending or descending.
  • Paging - On paging selected cells will be cleared. Selection wont be persisted across pages.
  • Filtering - When filtering is performed selection will not be cleared. If filtering is cleared it will return - the initially selected cells.
  • Resizing - On column resizing selected cells will not be cleared.
  • Hiding - It will not clear the selected cells. If column is hidden, the cells from the next visible column will be selected.
  • Pinning - Selected cell will not be cleared. Same as hiding
  • Group by - On column grouping selected cells will not be cleared.

Grid Row Selection

With row selection in Ignite UI for Angular, there is a checkbox that precedes all other columns within the row. When a user clicks on the checkbox, the row will either become selected or deselected, enabling the user to select multiple rows of data.

Demo

Selection Based Summaries

This sample demonstrates the usage of multiple selection along with custom summary functions. Change the selection to see summaries of the currently selected range.

Setup

Single Selection

The Grid single selection can be easily setup using the Grid's onSelection event. The event emits a reference to the cell component. That cell component has a reference to the row component that is holding it. The row component reference rowID getter can be used to pass a unique identifier for the row (using either rowData[primaryKey] or the rowData object itself) to the appropriate list of the selection. To make sure that only a single row is always selected, we empty the selection row selection list beforehand (the second argument in the selectRows method call):

<!-- selectionExample.component.html -->

<igx-grid #grid1 [data]="remote | async" [rowSelectable]="false" (onSelection)="handleRowSelection($event)"
    [width]="'800px'" [height]="'600px'" [allowFiltering]="true">
        ...
</igx-grid>
/* selectionExample.component.ts */

public handleRowSelection(args) {
    const targetCell = args.cell as IgxGridCellComponent;
    if (!this.selection) {
        this.grid1.selectRows([targetCell.row.rowID], true);
    }
}

Multiple Selection

To enable multiple row selection, the igx-grid exposes the rowSelectable property. Setting rowSelectable to true enables a select checkbox field on each row and in the Grid header. The checkbox allows users to select multiple rows, with the selection persisting through scrolling, paging, and data operations such as sorting and filtering:

<!-- selectionExample.component.html -->

<igx-grid #grid1 [data]="remote | async" [primaryKey]="'ProductID'" [rowSelectable]="selection" (onSelection)="handleRowSelection($event)"
    [width]="'800px'" [height]="'600px'" [allowFiltering]="true">
    ...
</igx-grid>
/* selectionExample.component.ts */

public selection = true;

Note: In order to have proper row selection and cell selection, while Grid has remote virtualization, primaryKey should be provided.

Note: If filtering is in place, selectAllRows() and deselectAllRows() select/deselect all filtered rows.

Note: When Grid has remote virtualization then clicking the header checkbox will select/deselect all records. But when all records are selected through header checkbox and then a visible row has been deselected, when new data is loaded in the Grid on demand, it is a limitation that the newly loaded rows are not selected.

Note: Cell selection will trigger onSelection and not onRowSelectionChange.

Styling

The theme engine exposes properties that allows us to style the range of selected cells.

Import theme

To get started with styling the selection, we need to import the index file, where all the theme functions and component mixins live:

// in component.scss
@import '~igniteui-angular/lib/core/styles/themes/index';

Define colors

Once done, we can make use of the igx-contrast-color and igx-color functions. With them, we define the colors we would like to use for our selection range:

    $text-color: igx-contrast-color($default-palette, 'primary', 900);
    $background-color: igx-color($default-palette, "primary", 900);
    $border-yellow: #f2c43c;

Create custom theme

Next we create a new theme that extends the igx-grid-theme passing our text-color, background-color and border-yellow variables as $cell-selected-text-color, $cell-selected-background and $cell-active-border-color, respectively:

$custom-grid-theme: igx-grid-theme(
    $cell-selected-text-color: $text-color,
    $cell-active-border-color: $border-yellow,
    $cell-selected-background: $background-color
);

Apply theme

Afterwards, all we need to do is include the mixin in our component's style (could also be in the app styles), so that our igx-grid uses the newly created theme instead of the default one:

    @include igx-grid($custom-grid-theme);
Note

If the component is using an Emulated ViewEncapsulation, it is necessary to penetrate this encapsulation using ::ng-deep. We scope the style under :host selector so as not to affect any other grids we might have in our application.

   :host { 
       ::ng-deep {
           @include igx-grid($custom-grid-theme);
       }
   }

With the custom theme applied, the selected grid cells are highlighted with our selected colors:

Demo


Code Snippets

Select rows programmatically

The below code example can be used to select one or multiple rows simultaneously (via primaryKey):

<!-- selectionExample.component.html -->

<igx-grid ... [primaryKey]="'ID'">
...
</igx-grid>
...
<button (click)="this.grid.selectRows([1,2,5])">Select 1,2 and 5</button>

This will add the rows which correspond to the data entries with IDs 1, 2 and 5 to the Grid selection.

Cancel selection event

<!-- selectionExample.component.html -->

<igx-grid (onRowSelectionChange)="handleRowSelectionChange($event)">
...
</igx-grid>
/* selectionExample.component.ts */

public handleRowSelectionChange(args) {
    args.newSelection = args.oldSelection; // overwrites the new selection, making it so that no new row(s) are entered in the selectionAPI
    args.checked = false; // overwrites the checkbox state
}

Grid Context Menu

Using the onContextMenu event you can add a custom context menu to facilitate your work with IgxGrid. With a right click on the grid's body, the event emits the cell on which it is triggered. The context menu will operate with the emitted cell.

If there is a multi-cell selection, we will put logic, which will check whether the selected cell is in the area of the multi-cell selection. If it is, we will also emit the values of the selected cells.

Basically the main function will look like this:

...
 public rightClick(eventArgs: any) {
     // Prevent the default behavior of the right click
    eventArgs.event.preventDefault();
    this.multiCellArgs = {};
    // If we have multi-cell selection, check if selected cell is within the ranges
    if (this.multiCellSelection) {
        const node = eventArgs.cell.selectionNode;
        const isCellWithinRange = this.grid1.getSelectedRanges().some(range => {
            if (node.column >= range.columnStart &&
                node.column <= range.columnEnd &&
                node.row >= range.rowStart &&
                node.row <= range.rowEnd) {
                return true;
            }
            return false;
        })
        // If the cell is within a multi-cell selection range, bind all the selected cells data
        if (isCellWithinRange) {
            this.multiCellArgs = { data: this.multiCellSelection.data };
        }
    }
    // Set the position of the context menu
    this.contextmenuX = eventArgs.event.clientX;
    this.contextmenuY = eventArgs.event.clientY;
    this.clickedCell = eventArgs.cell;
    // Enable the context menu
    this.contextmenu = true;
}
...

The context menu will have the following functions:

  • Copy the selected cell's value
  • Copy the selected cell's dataRow
  • If the selected cell is within a multi cell selection range, copy all the selected data
//contextmenu.component.ts
...
    public copySelectedCellData(event) {
        const selectedData = { [this.cell.column.field]: this.cell.value };
        this.copyData(JSON.stringify({ [this.cell.column.field]: this.cell.value }));
        this.onCellValueCopy.emit({ data: selectedData });
    }

    public copyRowData(event) {
        const selectedData = this.cell.row.rowData ;
        this.copyData(JSON.stringify(this.cell.row.rowData));
        this.onCellValueCopy.emit({ data: selectedData });
    }

    public copySelectedCells(event) {
        const selectedData = this.selectedCells.data;
        this.copyData(JSON.stringify(selectedData));
        this.onCellValueCopy.emit({ data: selectedData });
    }
...

The IgxGrid will fetch the copied data and will paste it in a container element.

The template we are going to use to combine the grid with the context menu:

<div class="wrapper">
    <div class="grid__wrapper" (window:click)="disableContextMenu()">
        <igx-grid #grid1 [data]="data" [autoGenerate]="false" height="500px" width="100%"
            (onContextMenu)="rightClick($event)" (onRangeSelection)="getCells($event)"
            (onSelection)="cellSelection($event)">
        <!-- Columns area -->
        </igx-grid>
        <div *ngIf="contextmenu==true">
            <contextmenu [x]="contextmenuX" [y]="contextmenuY" [cell]="clickedCell" [selectedCells]="multiCellArgs" (onCellValueCopy)="copy($event)">
            </contextmenu>
        </div>
    </div>
    <div class="selected-data-area">
        <div>
           <pre>{{copiedData}}</pre>
        </div>
    </div>
</div>

The result is:

API References

Additional Resources

Our community is active and always welcoming to new ideas.