DkGrid
  • Overview
  • Getting Started
    • Quick Start Tutorial
  • Fundamentals
    • Grid Structure
      • Grid Size
      • Header
      • Row Filter
      • Rows
      • Panels
      • Gutters
      • Edition Toolbar
      • Paginator
      • Borders
      • Column Context Menu
      • Waiting Indicator
    • DataSource
      • In-Memory DataSource
      • Custom DataSource
    • Theming
  • Columns
    • Column Definitions
    • Column Grouping
    • Column Sizing
    • Column Moving
    • Column Pinning
  • Rows
    • Row Sorting
    • Row Selection
    • Row Grouping
    • Row Pagination
  • Filtering
    • Column Filters
    • Filter types
    • In-line Filters
  • Editing
    • Row Edition
    • Edition templates
    • Edition validation
    • Multiple rows edition
  • Reference
    • DkGrid API
      • DkGridColumnDef
      • DkGridSorting
      • DkGridSelection
      • DkGridRowGrouping
      • DkGridPagination
      • DkGridWaitingIndicator
      • DkGridFactoryDataSource
      • DkGridFilter
      • DkGridEdition
    • Components
      • DkGridComponent
      • DkGridColumnComponent
    • Classes
      • DataSource
      • Columns
      • Rows
      • Filtering
      • Editing
    • Interfaces
      • Columns
      • Sorting
      • Row Grouping
      • Filtering
      • Editing
    • Injection Tokens
      • Grid Structure
      • Filtering
      • Editing
      • Theming
    • Type aliases
      • DataSource
      • Columns
      • Selection
      • Filtering
      • Editing
    • Type Guards
Powered by GitBook
On this page
  • Live example
  • Allowing the sorting operation
  • Sortable columns
  • Sorting rows through the UI
  • Clicking on the column header
  • Column Context Menu
  • DikeGrid Sorting API
  • Sort event
  • Summary
  • Complete code for this section
  1. Rows

Row Sorting

This section describes how you can sort the DikeGrid rows.

PreviousColumn PinningNextRow Selection

Last updated 2 years ago

Live example

live example.

Allowing the sorting operation

To allow the user to sort the DikeGrid rows, you must set a flag at the grid scope by providing an input property named allowSorting. Its default value is false.

row-sorting.component.html
<dike-grid id="grid-row-sorting" height="650px" #grid="dkgGrid"
    [allowSorting]="gridProperties.allowSorting">
</dike-grid>

You can change the value of the allowSorting property at runtime.

Open the for the live example and mark the Allow Sorting checkbox.

Sortable columns

If you want the user to sort the DikeGrid rows by a column, mark the column as sortable. Its default value is false.

You can only make sortable data columns, not column groups.

See the following column configuration:

row-sorting.component.html
<dike-grid id="grid-row-sorting" height="650px" #grid="dkgGrid"
    [allowSorting]="gridProperties.allowSorting">
    
    <dike-grid-column
        fieldName="employeeId"
        headerText="Employee Id"
        dataType="Text"
        width="350">
    </dike-grid-column>
    
    <dike-grid-column
        fieldName="personalInfoGroup"
        headerText="Personal Info">

        <dike-grid-column
            fieldName="completeNameGroup"
            headerText="Complete Name">

            <dike-grid-column
                fieldName="firstName"
                headerText="Name"
                dataType="Text"
                width="150"
                sortable>
            </dike-grid-column>

            <dike-grid-column
                fieldName="lastName"
                headerText="Surname"
                dataType="Text"
                width="150"
                sortable>
            </dike-grid-column>

        </dike-grid-column>

        <dike-grid-column
            fieldName="gender"
            headerText="Gender"
            dataType="Binary"
            width="130">
        </dike-grid-column>

        <dike-grid-column
            fieldName="age"
            headerText="Age"
            dataType="Numeric"
            contentAlign="center"
            width="100"
            sortable>
        </dike-grid-column>
    </dike-grid-column>

    <dike-grid-column
        fieldName="email"
        headerText="Email"
        dataType="Text"
        width="300">
    </dike-grid-column>

    <dike-grid-column
       fieldName="hireDate"
       headerText="Hire Date"
       dataType="Date"
       width="150"
       sortable>
    </dike-grid-column>
    
</dike-grid>

We have the following sortable columns with the previous configuration: Name and Surname under the Complete Name group, Age column under the Personal Info group, and the Hire Date column.

You can make a column sortable at runtime using the corresponding API. For example, see the following code snippet:

row-sorting.component.ts
onSetColumnSortable(): void {
  if (this.columnControl.valid) {
    // Get the selected column:
    const column = this.columnControl.value as DikeColumnDef;

    if (isDikeDataColumnDef(column)) {
      // Toggle the sortable flag for the selected column:
      this.dikeGrid.columnDef.setColumnSortable(column, !column.sortable);
    }
  }
}

As you can see, once you have got the column you want to set as sortable or non-sortable, use the DikeGridColumnDef service instance to change the column state.

Sorting rows through the UI

Once you define columns as sortable, you can sort the DikeGrid rows by these sortable columns.

Clicking on the column header

You can sort the DikeGrid rows by clicking on the column header.

When you have clicked on the column header of a sortable column, you will see an arrow that indicates the direction of the sorting operation.

Column Context Menu

DikeGrid Sorting API

You can sort the DikeGrid rows using the sorting API.

Before using the sorting API, you must retrieve the corresponding DikeGrid instance by querying the component's view.

<dike-grid id="grid-row-sorting" height="650px" #grid="dkgGrid">
</dike-grid>
@Component({
  selector: 'row-sorting',
  templateUrl: './row-sorting.component.html',
  styleUrls: ['./row-sorting.component.scss'],

  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class RowSortingComponent implements OnInit {
  // Retrieve the DikeGridComponent<T> instance from the view:
  @ViewChild('grid') dikeGrid: DikeGridComponent<Employee>;
  
  //...
}

The sorting API has the following methods:

Method
Description

sortBy()

It sorts the DikeGrid rows by the given column in the given direction.

isDikeGridSortedBy()

It evaluates if the DikeGrid is sorted by the given column.

getCurrentSortable()

It returns the column and the direction of the sorting operation. Otherwise, it returns null.

clearSorting()

It removes the current sorting operation.

You can sort the DikeGrid rows only by one column sortable at a time.

To see the use of the sorting API, we have created the following UI:

<form [formGroup]="rowSortingForm"
  class="mt-2 flex flex-row flex-wrap items-center justify-around">
  <mat-form-field appearance="fill" class="flex-none w-56 m-2">
    <mat-label>Columns</mat-label>
      <mat-select [formControl]="columnControl" (selectionChange)="onSelectionChange($event)" required>
          <mat-select-trigger>
            <div class="w-40 flex flex-row items-center justify-between">
                <div>{{ columnControl.value?.headerText }}</div>
                <mat-icon *ngIf="columnControl.value && columnControl.value.sortable">sort_by_alpha</mat-icon>
            </div>
          </mat-select-trigger>
          <mat-option *ngFor="let column of gridColumns" [value]="column" [disabled]="!!column.children">
              <div class="flex flex-row items-center justify-between">
                <div>{{ column.headerText }}</div>
                <mat-icon *ngIf="column.sortable">sort_by_alpha</mat-icon>
              </div>
          </mat-option>
      </mat-select>
    </mat-form-field>

  <mat-radio-group class="flex-none w-56 m-2 flex flex-row justify-around"
      #radioDirections="matRadioGroup" formControlName="direction" required>
      <mat-radio-button class="my-2" value="asc">asc</mat-radio-button>
      <mat-radio-button class="my-2" value="desc">desc</mat-radio-button>
  </mat-radio-group>

  <div class="flex-none w-56 flex flex-col m-2 items-center">
      <button mat-raised-button
          class="flex-none w-56 my-2"
          color="primary"
          [disabled]="!rowSortingForm.valid || radioDirections.disabled"
          (click)="onSortBy()">Sort by
      </button>

      <button mat-raised-button
          class="flex-none w-56 my-2"
          color="primary"
          [disabled]="!columnControl.valid"
          (click)="onSetColumnSortable()">Set column {{ columnControl.value?.sortable ? 'non-' : '' }}sortable
      </button>
  </div>
</form>

<dike-grid id="grid-row-sorting" height="650px" #grid="dkgGrid">
</dike-grid>
onSelectionChange(data: MatSelectChange): void {
  const column = data.value as DikeColumnDef;

  if (isDikeDataColumnDef(column)) {
    if (!column.sortable) {
      this.rowSortingForm.get('direction').disable();

    } else {
      this.rowSortingForm.get('direction').enable();
    }
  }
}

onSortBy(): void {
  if (this.rowSortingForm.valid) {
    const column = this.rowSortingForm.get('column').value as DikeColumnDef;
    const direction = this.rowSortingForm.get('direction').value as 'asc' | 'desc';

    // if the DikeGrid instance is sorted, get the current columns and the sort direction:
    const currentSortable = this.dikeGrid.sorting.getCurrentSortable();

    /**
     * We will sort the DikeGrid rows, if only if:
     *
     *    1. The DikeGrid is not sorted.
     *    2. Or, the DikeGrid is sorted but the selected column is different than the current column.
     *    3. Or, the DikeGrid is sorted by the selected column but the selected direction is different.
     */
    if (isDikeDataColumnDef(column) &&
      (!currentSortable || currentSortable.sortedColumn.columnId !== column.columnId || currentSortable.type !== direction)) {
      this.dikeGrid.sorting.sortBy(column, direction);
    }
  }
}

onSetColumnSortable(): void {
  if (this.columnControl.valid) {
    // Get the selected column:
    const column = this.columnControl.value as DikeColumnDef;

    if (isDikeDataColumnDef(column)) {
      // Toggle the sortable flag for the selected column:
      this.dikeGrid.columnDef.setColumnSortable(column, !column.sortable);
    }
  }
}

The previous HTML code generates the following output:

With the previous UI, you can do the following tasks:

  1. You can choose any data column from the dropdown control. Sortable columns have an icon indicating they are sortable.

  2. You can change the sortable state of a data column.

  3. To sort the DikeGrid rows, you must select the direction of the sorting operation. Then click on the Sort By button.

<dike-grid id="grid-row-sorting" height="650px" #grid="dkgGrid"
    (columnsChange)="onColumnsChange($event)">
</dike-grid>
onColumnsChange(columns: DikeColumnDef[]): void {
    this.gridColumns = this.flatColumns(columns);
    // Clear selection:
    this.rowSortingForm.patchValue({ column: null, direction: '' });
}

Every time we receive a new set of columns, we flat them into a single array, invoking the method flatColumns(). So indeed, we are flattening the column groups, traversing them recursively.

row-sorting.component.ts
private flatColumns(columns: DikeColumnDef[]): DikeColumnDef[] {
  return columns.reduce((accum, column) => {
    if (isDikeGroupColumnDef(column) && !!column.children && column.children.length > 0) {
      return [ ...accum, column, ...this.flatColumns(column.children) ];
    }

    return [ ...accum, column ];
  }, [ ]);
}

If you see the content of the dropdown control, you see the columns Employee Id, Personal Info group, Complete Name group, then Name and Surname columns, etc.

The column groups are disabled, such as Personal Info and Complete Name.

Sort event

Every time we sort the DikeGrid rows, the DikeGrid instance emits the related event.

<dike-grid id="grid-row-sorting" height="650px" #grid="dkgGrid"
    (sortChange)="onSortChange($event)">
</dike-grid>
onSortChange(sortedBy: DikeColumnSortEvent<Employee>): void {
  console.log('Sort change: ', sortedBy);
}

The emitted object is of type DikeColumnSortEvent, which contains the column and the direction of the current sorting operation.

Open the dev console to see the output of the sortChange event.

Summary

To perform the sorting operation, you must allow it by providing an input property named allowSorting. Then, when creating columns, you can define them as sortable. Nevertheless, you can change their state at runtime using the related API. You can perform the sorting operation through the UI or the sorting API.

Complete code for this section

<form [formGroup]="rowSortingForm"
  class="mt-2 flex flex-row flex-wrap items-center justify-around">
  <mat-form-field appearance="fill" class="flex-none w-56 m-2">
    <mat-label>Columns</mat-label>
      <mat-select [formControl]="columnControl" (selectionChange)="onSelectionChange($event)" required>
          <mat-select-trigger>
            <div class="w-40 flex flex-row items-center justify-between">
                <div>{{ columnControl.value?.headerText }}</div>
                <mat-icon *ngIf="columnControl.value && columnControl.value.sortable">sort_by_alpha</mat-icon>
            </div>
          </mat-select-trigger>
          <mat-option *ngFor="let column of gridColumns" [value]="column" [disabled]="!!column.children">
              <div class="flex flex-row items-center justify-between">
                <div>{{ column.headerText }}</div>
                <mat-icon *ngIf="column.sortable">sort_by_alpha</mat-icon>
              </div>
          </mat-option>
      </mat-select>
    </mat-form-field>
    
      <mat-radio-group class="flex-none w-56 m-2 flex flex-row justify-around"
          #radioDirections="matRadioGroup" formControlName="direction" required>
          <mat-radio-button class="my-2" value="asc">asc</mat-radio-button>
          <mat-radio-button class="my-2" value="desc">desc</mat-radio-button>
      </mat-radio-group>
    
      <div class="flex-none w-56 flex flex-col m-2 items-center">
          <button mat-raised-button
              class="flex-none w-56 my-2"
              color="primary"
              [disabled]="!rowSortingForm.valid || radioDirections.disabled"
              (click)="onSortBy()">Sort by
          </button>

          <button mat-raised-button
              class="flex-none w-56 my-2"
              color="primary"
              [disabled]="!columnControl.valid"
              (click)="onSetColumnSortable()">Set column {{ columnControl.value?.sortable ? 'non-' : '' }}sortable
          </button>
      </div>
</form>

<dike-grid id="grid-row-sorting" height="650px" #grid="dkgGrid"
    [displayRowId]="gridProperties.displayRowId"
    [gridElevation]="gridProperties.matElevation"
    [gridElevationValue]="gridProperties.elevationValue"
    [striped]="gridProperties.stripeRows"
    [verticalRowLines]="gridProperties.verticalRowLines"

    (columnsChange)="onColumnsChange($event)"
    (sortChange)="onSortChange($event)"

    [allowSorting]="gridProperties.allowSorting"
    [datasource]="dkgDataSource">

    <dike-grid-column
        fieldName="employeeId"
        headerText="Employee Id"
        dataType="Text"
        width="350">
    </dike-grid-column>

    <dike-grid-column
        fieldName="personalInfoGroup"
        headerText="Personal Info">

        <dike-grid-column
            fieldName="completeNameGroup"
            headerText="Complete Name">

            <dike-grid-column
                fieldName="firstName"
                headerText="Name"
                dataType="Text"
                width="150"
                sortable>
            </dike-grid-column>

            <dike-grid-column
                fieldName="lastName"
                headerText="Surname"
                dataType="Text"
                width="150"
                sortable>
            </dike-grid-column>

        </dike-grid-column>

        <dike-grid-column
            fieldName="gender"
            headerText="Gender"
            dataType="Binary"
            width="130">
        </dike-grid-column>

        <dike-grid-column
            fieldName="age"
            headerText="Age"
            dataType="Numeric"
            contentAlign="center"
            width="100"
            sortable>
        </dike-grid-column>
    </dike-grid-column>

    <dike-grid-column
        fieldName="email"
        headerText="Email"
        dataType="Text"
        width="300">
    </dike-grid-column>

    <dike-grid-column
        fieldName="hireDate"
        headerText="Hire Date"
        dataType="Date"
        width="150"
        sortable>
    </dike-grid-column>
</dike-grid>
import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, OnInit, ViewChild, ViewEncapsulation } from '@angular/core';
import { FormControl, FormGroup, Validators } from '@angular/forms';
import { MatSelectChange } from '@angular/material/select';

import { Subscription } from 'rxjs';

import { DikeColumnDef, DikeColumnSortEvent, DikeGridComponent, 
  DikeGridDataSourceInput, isDikeDataColumnDef, isDikeGroupColumnDef 
} from '@dikesoft/angular-data-grid';

import { DikeGridProperties } from 'app/core/config/dike-grid.properties';
import { Employee } from 'app/mock-api/common/employees/data.model';

import { DikeGridConfig } from 'app/services/dike-grid.config.service';
import { SampleData } from 'app/services/sample-data.service';

@Component({
  selector: 'row-sorting',
  templateUrl: './row-sorting.component.html',
  styleUrls: ['./row-sorting.component.scss'],

  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush
})
export class RowSortingComponent implements OnInit, OnDestroy {
  // Retrieve the DikeGridComponent<T> instance from the view:
  @ViewChild('grid') dikeGrid: DikeGridComponent<Employee>;

  dkgDataSource: DikeGridDataSourceInput<Employee>;
  gridProperties: DikeGridProperties;

  gridColumns: DikeColumnDef[];
  rowSortingForm: FormGroup;
  columnControl: FormControl;

  private changeGridPropertiesSubscription: Subscription = Subscription.EMPTY;

  constructor(
    private cdr: ChangeDetectorRef,
    private gridConfig: DikeGridConfig,
    private sampleData: SampleData) { }

  ngOnInit(): void {
    this.dkgDataSource = this.sampleData.getEmployees(1000);
    // Listening to any config property change:
    this.setChangeGridPropertiesSubscription();
    this.createForm();
  }
  
  ngOnDestroy(): void {
    this.changeGridPropertiesSubscription.unsubscribe();
  }

  onSelectionChange(data: MatSelectChange): void {
    const column = data.value as DikeColumnDef;

    if (isDikeDataColumnDef(column)) {
      if (!column.sortable) {
        this.rowSortingForm.get('direction').disable();

      } else {
        this.rowSortingForm.get('direction').enable();
      }
    }
  }

  onSortBy(): void {
    if (this.rowSortingForm.valid) {
      const column = this.rowSortingForm.get('column').value as DikeColumnDef;
      const direction = this.rowSortingForm.get('direction').value as 'asc' | 'desc';

      // if the DikeGrid instance is sorted, get the current columns and the sort direction:
      const currentSortable = this.dikeGrid.sorting.getCurrentSortable();

      /**
       * We will sort the DikeGrid rows, if only if:
       *
       *    1. The DikeGrid is not sorted.
       *    2. Or, the DikeGrid is sorted but the selected column is different than the current column.
       *    3. Or, the DikeGrid is sorted by the selected column but the selected direction is different.
       */
      if (isDikeDataColumnDef(column) &&
        (!currentSortable || currentSortable.sortedColumn.columnId !== column.columnId || currentSortable.type !== direction)) {
        this.dikeGrid.sorting.sortBy(column, direction);
      }
    }
  }

  onSetColumnSortable(): void {
    if (this.columnControl.valid) {
      // Get the selected column:
      const column = this.columnControl.value as DikeColumnDef;

      if (isDikeDataColumnDef(column)) {
        // Toggle the sortable flag for the selected column:
        this.dikeGrid.columnDef.setColumnSortable(column, !column.sortable);
      }
    }
  }

  onSortChange(sortedBy: DikeColumnSortEvent<Employee>): void {
    console.log('Sort change: ', sortedBy);
  }

  onColumnsChange(columns: DikeColumnDef[]): void {
    this.gridColumns = this.flatColumns(columns);
    // Clear selection:
    this.rowSortingForm.patchValue({ column: null, direction: '' });
  }

  private flatColumns(columns: DikeColumnDef[]): DikeColumnDef[] {
    return columns.reduce((accum, column) => {
      if (isDikeGroupColumnDef(column) && !!column.children && column.children.length > 0) {
        return [ ...accum, column, ...this.flatColumns(column.children) ];
      }

      return [ ...accum, column ];
    }, [ ]);
  }

  private createForm(): void {
    this.columnControl = new FormControl(null, Validators.required);

    this.rowSortingForm = new FormGroup({
      column: this.columnControl,
      direction: new FormControl({ value: '', disabled: false }, Validators.required),
    });
  }

  private setChangeGridPropertiesSubscription(): void {
    this.changeGridPropertiesSubscription.unsubscribe();
    this.changeGridPropertiesSubscription = this.gridConfig.configChange.subscribe((props: DikeGridProperties) => {
      this.gridProperties = props;
      this.cdr.markForCheck();
    });
  }
}

Before using the column API, you must grab the instance of the service.

When you define a column as sortable, you will see the sorting submenu in the . Then, you will see the sorting options.

The sorting API is an instance of type under the through the read-only property named sorting.

For further details, see the definition.

It is essential to notice that we are listening to any change in the DikeGrid's columns, attaching a callback to the columnsChange output property from the .

You can also listen to the sortChange event from the instance.

DikeGridColumnDef
Column Context Menu
DikeGridSorting
DikeGridComponent
DikeGridComponent
Row Sorting
Floating Configuration Panel
Floating Configuration Panel - Sorting
Sorting by Name column clicking on the column header
Sorting By Name column using the Column Context Menu
Row sorting using the API
Flattening column groups
DikeGridSorting
DikeGridSorting