All Components

Grid Overview

The Grid displays data in a tabular format and provides a full spectrum of configuration options.

Basic Usage

The following example demonstrates the Grid in action.

@Component({
    selector: 'my-app',
    template: `
        <kendo-grid [data]="gridData">
            <kendo-grid-column field="ProductID" title="Product ID" width="120">
            </kendo-grid-column>
            <kendo-grid-column field="ProductName" title="Product Name">
            </kendo-grid-column>
            <kendo-grid-column field="UnitPrice" title="Unit Price" width="230">
            </kendo-grid-column>
            <kendo-grid-column field="Discontinued" width="120">
                <template kendoCellTemplate let-dataItem>
                    <input type="checkbox" [checked]="dataItem.Discontinued" disabled/>
                </template>
            </kendo-grid-column>
        </kendo-grid>
    `
})
class AppComponent {
    private gridData: any[] = [{
        "ProductID": 1,
        "ProductName": "Chai",
        "UnitPrice": 18.0000,
        "Discontinued": true
    }, {
        "ProductID": 2,
        "ProductName": "Chang",
        "UnitPrice": 19.0000,
        "Discontinued": false
    }, {
        "ProductID": 3,
        "ProductName": "Aniseed Syrup",
        "UnitPrice": 10.0000,
        "Discontinued": false
    }, {
        "ProductID": 4,
        "ProductName": "Chef Anton's Cajun Seasoning",
        "UnitPrice": 22.0000,
        "Discontinued": false
    }, {
        "ProductID": 5,
        "ProductName": "Chef Anton's Gumbo Mix",
        "UnitPrice": 21.3500,
        "Discontinued": false
    }, {
        "ProductID": 6,
        "ProductName": "Grandma's Boysenberry Spread",
        "UnitPrice": 25.0000,
        "Discontinued": false
    }];
}

Installation

  1. The Grid package is published on the Progress NPM Registry. To set up your access, follow the steps in Installation.

  2. Download and install the package:

    npm install --save @progress/kendo-angular-grid
  3. Once installed, import the GridModule in your application root module:

    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { GridModule } from '@progress/kendo-angular-grid';
    import { AppComponent } from './app.component';
    
    @NgModule({
        bootstrap:    [AppComponent],
        declarations: [AppComponent],
        imports:      [BrowserModule, GridModule]
    })
    export class AppModule {
    }

Dependencies

The Grid package requires the following peer dependencies that have to be installed by your application:

  • @angular/common
  • @angular/core
  • @progress/kendo-data-query
  • rxjs

The following dependencies will be installed automatically:

  • @progress/kendo-angular-intl

Configuration

The configuration options provided by the Grid allow you to:

Columns

Header Template

You can use the header template to customize the cell of the column table header or to format the data it displays. To define a header template, nest a <template> tag with the kendoHeaderTemplate directive inside <kendo-grid-column>.

The template context is set to the current column and then the following additional fields are passed:

  • column—Defines an instance of the ColumnComponent option.
  • columnIndex—Defines the current column index.
@Component({
    selector: 'my-app',
    template: `
        <kendo-grid [data]="gridData">
            <kendo-grid-column field="ProductName">
                <template kendoHeaderTemplate let-column let-columnIndex="columnIndex">
                  {{column.field}}({{columnIndex}})
                </template>
            </kendo-grid-column>
             <kendo-grid-column field="UnitPrice">
                <template kendoHeaderTemplate let-column let-columnIndex="columnIndex">
                  {{column.field}}({{columnIndex}})
                </template>
            </kendo-grid-column>
        </kendo-grid>
    `
})
class AppComponent {
    private gridData: any[] = [{
        "ProductID": 1,
        "ProductName": "Chai",
        "UnitPrice": 18.0000,
        "Discontinued": false
    }];
}

Cell Template

You can use the cell template to customize the cell content or to format the cell data that is displayed. To define a cell template, nest a <template> tag with the kendoCellTemplate directive inside <kendo-grid-column>.

The template context is set to the current data item and the following additional fields are passed:

  • columnIndex—Defines the current column index.
  • rowIndex—Defines the current row index.
  • dataItem—Defines the current data item.
  • column—Defines the current column instance.
@Component({
    selector: 'my-app',
    template: `
        <kendo-grid [data]="gridData">
            <kendo-grid-column field="ProductName">
                <template kendoCellTemplate let-dataItem let-rowIndex="rowIndex">
                    Row: {{rowIndex}} /
                    <strong>{{dataItem.ProductName}}</strong>
                    ({{dataItem.Discontinued ? "discontinued" : "active"}})
                </template>
            </kendo-grid-column>
        </kendo-grid>
    `
})
class AppComponent {
    private gridData: any[] = [{
        "ProductID": 1,
        "ProductName": "Chai",
        "UnitPrice": 18.0000,
        "Discontinued": false
    }, {
        "ProductID": 2,
        "ProductName": "Chang",
        "UnitPrice": 19.0000,
        "Discontinued": true
    }];
}

You can use the footer template to customize the cell of the table column footer or to format the data it displays. To define a footer template, nest a <template> tag with the kendoFooterTemplate directive inside <kendo-grid-column>.

The template context is set to the current column and the following additional fields are passed:

  • column—Defines an instance of the ColumnComponent option.
  • columnIndex—Defines the current column index.
@Component({
    selector: 'my-app',
    template: `
        <kendo-grid [data]="gridData">
            <kendo-grid-column field="ProductName">
                <template kendoFooterTemplate let-column let-columnIndex="columnIndex">
                  {{column.field}}({{columnIndex}})
                </template>
            </kendo-grid-column>
             <kendo-grid-column field="UnitPrice">
                <template kendoFooterTemplate let-column let-columnIndex="columnIndex">
                  {{column.field}}({{columnIndex}})
                </template>
            </kendo-grid-column>
        </kendo-grid>
    `
})
class AppComponent {
    private gridData: any[] =  [{
        "ProductID": 1,
        "ProductName": "Chai",
        "UnitPrice": 18.0000,
        "Discontinued": false
    }];
}

Data Binding of Columns

To bind the Grid columns to complex fields, set the kendoCellTemplate option.

@Component({
    selector: 'my-app',
    template: `
        <kendo-grid [data]="gridData">
          <kendo-grid-column field="ProductName" title="Product Name" width="160">
          </kendo-grid-column>
          <kendo-grid-column field="Category" title="Category" width="400">
              <template kendoCellTemplate let-dataItem>
                  <div *ngIf="dataItem.Category">
                    <header>{{dataItem.Category?.CategoryName}}</header>
                    <span>{{dataItem.Category?.Description}}</span>
                  </div>
              </template>
          </kendo-grid-column>
          <kendo-grid-column field="UnitPrice" title="Unit Price" width="120">
          </kendo-grid-column>
        </kendo-grid>
    `
})
class AppComponent {
    private gridData: any[] = [{
        "ProductID": 1,
        "ProductName": "Chai",
        "UnitPrice": 18.0000,
        "Discontinued": false,
        "Category": {
            "CategoryID": 1,
            "CategoryName": "Beverages",
            "Description": "Soft drinks, coffees, teas, beers, and ales"
        }
    }, {
        "ProductID": 2,
        "ProductName": "Chang",
        "UnitPrice": 19.0000,
        "Discontinued": false,
        "Category": {
            "CategoryID": 1,
            "CategoryName": "Beverages",
            "Description": "Soft drinks, coffees, teas, beers, and ales"
        }
    }, {
        "ProductID": 3,
        "ProductName": "Aniseed Syrup",
        "UnitPrice": 10.0000,
        "Discontinued": false,
        "Category": {
            "CategoryID": 2,
            "CategoryName": "Condiments",
            "Description": "Sweet and savory sauces, relishes, spreads, and seasonings"
        }
  }];
}

If the Grid columns are not explicitly configured, the Grid auto-generates them and establishes their number depending on the data fields the Grid is bound to.

@Component({
    selector: 'my-app',
    template: `
        <kendo-grid [data]="gridData"></kendo-grid>
    `
})
class AppComponent {
    private gridData: any[] = [{
        "ProductID": 1,
        "ProductName": "Chai",
        "UnitPrice": 18.0000,
        "Discontinued": false
    }, {
        "ProductID": 2,
        "ProductName": "Chang",
        "UnitPrice": 19.0000,
        "Discontinued": false
  }];
}

Locking

Locked (frozen) columns allow some columns to be visible at all times while scrolling the Grid horizontally. The Grid supports frozen columns on one side of the table.

For the feature to work properly, the Grid has to meet the following requirements:

  • Scrolling has to be enabled.
  • The height option of the Grid has to be set.
  • The widths of all Grid columns have to be explicitly set in pixels so that the Grid is able to adjust the layout of the frozen and non-frozen columns.
  • The detail template does not work with locked columns.
  • It is not possible to touch-scroll frozen columns, because they are wrapped in a container with the overflow:hidden style. To work around this limitation on desktop devices, use the mousewheel event. A workaround for touch devices is not currently available.

Showing and Hiding

To show or hide a particular Grid column, use the *ngIf directive.

@Component({
    selector: 'my-app',
    template: `
        <button (click)="restoreColumns()">Restore hidden columns</button>

        <kendo-grid [data]="gridData">
          <template ngFor [ngForOf]="columns" let-column>
            <kendo-grid-column
              field="{{column}}"
              *ngIf="hiddenColumns.indexOf(column) === -1"
            >
              <template kendoHeaderTemplate let-dataItem>
                  {{dataItem.field}}
                  <button
                    (click)="hideColumn(dataItem.field)"
                  >
                    hide
                  </button>
              </template>
            </kendo-grid-column>
          </template>
        </kendo-grid>
    `
})
class AppComponent {
    private gridData: any[] = [{
        "ProductID": 1,
        "ProductName": "Chai",
        "UnitPrice": 18.0000,
        "Discontinued": false
    }];
    private hiddenColumns: string[] = [];
    private columns: string[] = ["ProductName", "Discontinued", "UnitPrice"];

    private restoreColumns(): void {
        this.hiddenColumns.length = 0;
    }

    private hideColumn(field: string): void {
      this.hiddenColumns.push(field);
    }
}

Styling

You can add a custom CSS class or style to the header, footer, and cell elements of the current column by using the following <kendo-grid-column> options:

  • headerClass—Specifies the class to be added to the header cell.
  • headerStyle—Specifies the styles to be added to the header cell.
  • class—Specifies the class to be added to the cell.
  • style—Specifies the styles to be added to the cell.
  • footerClass—Specifies the class to be added to the footer cell.
  • footerStyle—Specifies the styles to be added to the footer cell.
@Component({
    selector: 'my-app',
    template: `
        <kendo-grid [data]="gridData">
            <kendo-grid-column
              field="ProductName"
              [headerStyle]="{'border': '1px solid red'}"
              [style]="{'background': 'linear-gradient(red, yellow)'}"
              [footerStyle]="{'border': '1px solid yellow'}"
            >
              <template kendoFooterTemplate>Products count 1</template>
            </kendo-grid-column>
        </kendo-grid>
    `
})
class AppComponent {
    private gridData: any[] = [{
        "ProductID": 1,
        "ProductName": "Chai",
        "UnitPrice": 18.0000,
        "Discontinued": false
    }];
}

Scroll Modes

The Grid supports three layout modes:

  • Scrollable
  • Non-scrollable
  • Virtual scrolling

Scrollable

When scrolling is enabled, the Grid content is rendered as tables—one for the header area, another one for the scrollable data area, and a third one for the footer area. This behavior ensures that the header and footer areas of the Grid are always visible while the user scrolls vertically.

The scrollable mode is enabled by default. To configure it, use the scrollable option, which also requires you to set the height configuration of the Grid.

Non-Scrollable

When the non-scrollable mode is enabled, the Grid renders its data as a single table and the scroller is not displayed. To configure the non-scrollable mode, set the none value of the scrollable option.

Virtual Scrolling

Virtual scrolling optimizes performance—while the user is scrolling the content, it enables the Grid to display only part of the complete data without showing a pager.

The virtual scrolling mode requires you to set the height of the Grid. You also need to know the data or detail row height and the number of records beforehand. To provide the required data portion, you need to handle the pageChange event yourself.

When configuring the virtual scrolling, set up the following options:

  • (Required) height—By default, the height option is set to "300px".
  • (Required) rowHeight
  • (Required) skip
  • (Required) pageSize
  • (Required) data—Set the data option to use GridDataResult with the total field configured.
  • (Optional) detailRowHeight—Set the detailRowHeight option only when using a detail row.

To configure the virtual scrolling mode, set the virtual value of the scrollable option.

import {
  GridDataResult,
  PageChangeEvent
} from '@progress/kendo-angular-grid';

@Component({
  selector: 'my-app',
  template: `
      <kendo-grid
          [data]="gridView"
          [skip]="skip"
          [pageSize]="pageSize"
          [scrollable]="'virtual'"
          [rowHeight]="36"
          [height]="300"
          (pageChange)="pageChange($event)"
        >
        <kendo-grid-column field="id" [width]="50" title="ID"></kendo-grid-column>
        <kendo-grid-column field="firstName" title="First Name" [width]="120"></kendo-grid-column>
        <kendo-grid-column field="lastName" title="Last Name" [width]="120"></kendo-grid-column>
        <kendo-grid-column field="city" title="City" [width]="120"></kendo-grid-column>
        <kendo-grid-column field="title" title="Title" [width]="120"></kendo-grid-column>
      </kendo-grid>
  `
})
class AppComponent {
    private gridView: GridDataResult;
    private data: any[];
    private pageSize: number = 100;
    private skip: number = 0;

    constructor() {
        this.data = this.createRandomData(100000);
        this.loadProducts();
    }

    protected pageChange(event: PageChangeEvent): void {
        this.skip = event.skip;
        this.loadProducts();
    }

    private loadProducts(): void {
        this.gridView = {
            data: this.data.slice(this.skip, this.skip + this.pageSize),
            total: this.data.length
        };
    }

    /* Generating example data */
    private createRandomData(count: number) {
        const firstNames = ["Nancy", "Andrew", "Janet", "Margaret", "Steven", "Michael", "Robert", "Laura", "Anne", "Nige"],
            lastNames = ["Davolio", "Fuller", "Leverling", "Peacock", "Buchanan", "Suyama", "King", "Callahan", "Dodsworth", "White"],
            cities = ["Seattle", "Tacoma", "Kirkland", "Redmond", "London", "Philadelphia", "New York", "Seattle", "London", "Boston"],
            titles = ["Accountant", "Vice President, Sales", "Sales Representative", "Technical Support", "Sales Manager", "Web Designer",
            "Software Developer", "Inside Sales Coordinator", "Chief Technical Officer", "Chief Execute Officer"];

        return Array(count).fill({}).map((_, idx) => ({
                id: idx + 1,
                firstName: firstNames[Math.floor(Math.random() * firstNames.length)],
                lastName: lastNames[Math.floor(Math.random() * lastNames.length)],
                city: cities[Math.floor(Math.random() * cities.length)],
                title: titles[Math.floor(Math.random() * titles.length)]
            })
        );
    }
}

Sorting

The Grid enables you to sort single and multiple data-bound columns through the sortable option.

To properly handle the sorting functionality, set the field option of the column. When sortable is configured and the user tries to sort a column, the sortChange event is emitted. You need to handle the sortChange event and sort the data yourself.

import {
  GridDataResult,
} from '@progress/kendo-angular-grid';

import {
  SortDescriptor,
  orderBy
} from '@progress/kendo-data-query';

@Component({
  selector: 'my-app',
  template: `
      <kendo-grid
          [data]="gridView"
          [sortable]="{ mode: 'multiple' }"
          [sort]="sort"
          (sortChange)="sortChange($event)"
        >
        <kendo-grid-column field="ProductID" title="Product ID" width="120">
        </kendo-grid-column>
        <kendo-grid-column field="ProductName" title="Product Name">
        </kendo-grid-column>
        <kendo-grid-column field="UnitPrice" title="Unit Price" width="230">
        </kendo-grid-column>
      </kendo-grid>
  `
})
class AppComponent {
    private sort: SortDescriptor[] = [];
    private gridView: GridDataResult;
    private products: any[] = [{
        "ProductID": 1,
        "ProductName": "Chai",
        "UnitPrice": 18.0000,
        "Discontinued": false
    },{
        "ProductID": 2,
        "ProductName": "Chang",
        "UnitPrice": 19.0000,
        "Discontinued": false
    }];

    constructor() {
        this.loadProducts();
    }

    protected sortChange(sort: SortDescriptor[]): void {
        this.sort = sort;
        this.loadProducts();
    }

    private loadProducts(): void {
        this.gridView = {
            data: orderBy(this.products, this.sort),
            total: this.products.length
        };
    }
}

Paging

Paging is enabled through the pageable, pageSize, and skip options of the Grid. You have to handle the pageChange event that is emitted and sort the data yourself.

import {
  GridDataResult,
  PageChangeEvent
} from '@progress/kendo-angular-grid';

@Component({
  selector: 'my-app',
  template: `
      <kendo-grid
          [data]="gridView"
          [pageSize]="pageSize"
          [skip]="skip"
          [pageable]="true"
          [height]="300"
          (pageChange)="pageChange($event)"
        >
      </kendo-grid>
  `
})
class AppComponent {
    private gridView: GridDataResult;
    private data: Object[];
    private pageSize: number = 10;
    private skip: number = 0;

    private products: any[] = Array(100).fill({}).map((x, idx) => ({
        "ProductID": idx,
        "ProductName": "Product" + idx,
        "Discontinued": idx % 2 === 0
    }));

    constructor() {
        this.loadProducts();
    }

    protected pageChange(event: PageChangeEvent): void {
        this.skip = event.skip;
        this.loadProducts();
    }

    private loadProducts(): void {
        this.gridView = {
            data: this.products.slice(this.skip, this.skip + this.pageSize),
            total: this.products.length
        };
    }
}

Pager Types

The pager types of the Grid are:

  • Numeric—Renders buttons with numbers.
  • Input—Renders an input filed for typing the page number.

To set the pager types, pass the PagerSettings object to the pageable option of the Grid.

The PagerSettings object has the following fields:

  • buttonCount—This field sets the maximum numeric buttons count before the buttons are collapsed.
  • info—Toggles the information about the current page and the total number of records.
  • type—Accepts the numeric (buttons with numbers) and input (input for typing the page number) values.
  • pageSizes—Shows a menu for selecting the page size.
  • previousNext—Toggles the Previous and Next buttons.
@Component({
  selector: 'my-app',
  template: `
    <ul class="configurator">
      <li>
        <label for="type">Type of the pager:
            <select id="type" [(ngModel)]="type">
                <option value="numeric">Numeric</option>
                <option value="input">Input</option>
            </select>
        </label>
      </li>
      <li>
        <label for="buttonCount">Maximum number of buttons:
            <input id="buttonCount" class="k-textbox" type="number" [(ngModel)]="buttonCount"/>
        </label>
      </li>
      <li>
        <label for="info"><input id="info" type="checkbox" [(ngModel)]="info">Show info</label>
      </li>
      <li>
        <input id="pageSizes" type="checkbox" [(ngModel)]="pageSizes">
        <label for="pageSizes">Show page sizes</label><br>
      </li>
      <li>
        <input id="previousNext" type="checkbox" [(ngModel)]="previousNext">
        <label for="previousNext">Show previous / next buttons</label><br>
      </li>
     </ul>

      <kendo-grid
          [data]="gridView"
          [pageSize]="pageSize"
          [skip]="skip"
          [pageable]="{
            buttonCount: buttonCount,
            info: info,
            type: type,
            pageSizes: pageSizes,
            previousNext: previousNext
          }"
          [scrollable]="'none'"
          (pageChange)="pageChange($event)"
        >
      </kendo-grid>
  `
})
class AppComponent {
    private gridView: GridDataResult;

    private buttonCount: number =  5;
    private info: boolean = true;
    private type: 'numeric' | 'input' = 'numeric';
    private pageSizes: boolean = true;
    private previousNext: boolean = true;

    private pageSize: number = 5;
    private skip: number = 0;
    private products: any[] = Array(100).fill({}).map((x, idx) => ({
        "ProductID": idx,
        "ProductName": "Product" + idx,
        "Discontinued": idx % 2 === 0
    }));

    constructor() {
        this.loadProducts();
    }

    protected pageChange({ skip, take }: PageChangeEvent): void {
        this.skip = skip;
        this.pageSize = take;
        this.loadProducts();
    }

    private loadProducts(): void {
        this.gridView = {
            data: this.products.slice(this.skip, this.skip + this.pageSize),
            total: this.products.length
        };
    }
}

Selection

Currently, the Grid supports a single-row selection which is enabled through the selectable option. The highlighted state can be toggled on and off by clicking on the row. The selected row index is provided through the selectionChange event.

@Component({
  selector: 'my-app',
  template: `
      <kendo-grid
          [data]="gridView"
          [selectable]="true"
        >
      </kendo-grid>
  `
})

class AppComponent {
    private gridView: any[] = [{
        "ProductID": 1,
        "ProductName": "Chai",
        "UnitPrice": 18.0000,
        "Discontinued": false
    }, {
        "ProductID": 2,
        "ProductName": "Chang",
        "UnitPrice": 19.0000,
        "Discontinued": false
  }];
}

Detail Template

The detail Grid template enables you to provide additional details about a particular data row by expanding and collapsing its content.

  • The detail template does not work with locked columns.
  • To use the detail template for virtual scrolling, you have to set the detailRowHeight option.

To define the detail template, nest a <template> tag with the kendoDetailTemplate directive inside the <kendo-grid> tag. The template context is set to the current dataItem and the following additional fields are passed:

  • dataItem—Defines the current data item.
  • rowIndex—Defines the current row index.
@Component({
  selector: 'my-app',
  template: `
      <kendo-grid
          [data]="gridView"
          [selectable]="true"
          [scrollable]="'none'"
        >
        <kendo-grid-column field="ProductID" [width]="80"></kendo-grid-column>
        <kendo-grid-column field="ProductName" [width]="120"></kendo-grid-column>
        <kendo-grid-column field="UnitPrice" [width]="120"></kendo-grid-column>
        <kendo-grid-column field="Discontinued" [width]="80"></kendo-grid-column>
        <template kendoDetailTemplate let-dataItem>
          <section *ngIf="dataItem.Category">
            <header>{{dataItem.Category?.CategoryName}}</header>
            <article>{{dataItem.Category?.Description}}</article>
          </section>
        </template>
      </kendo-grid>
  `
})
class AppComponent {
    private gridView: any[] = [{
        "ProductID": 1,
        "ProductName": "Chai",
        "UnitPrice": 18.0000,
        "Discontinued": false,
        "Category": {
            "CategoryID": 1,
            "CategoryName": "Beverages",
            "Description": "Soft drinks, coffees, teas, beers, and ales"
        }
    }, {
        "ProductID": 2,
        "ProductName": "Chang",
        "UnitPrice": 19.0000,
        "Discontinued": false,
        "Category": {
            "CategoryID": 1,
            "CategoryName": "Beverages",
            "Description": "Soft drinks, coffees, teas, beers, and ales"
        }
    }, {
        "ProductID": 3,
        "ProductName": "Aniseed Syrup",
        "UnitPrice": 10.0000,
        "Discontinued": false,
        "Category": {
            "CategoryID": 2,
            "CategoryName": "Condiments",
            "Description": "Sweet and savory sauces, relishes, spreads, and seasonings"
        }
    }];
}

Data Binding

For more information on how to handle data operation processing, refer to the article on data binding.

Editing

For more information on how to use the editing functionality, refer to the article on editing.

In this article