Use Font Awesome instead of Kendo UI Icons

Some scenarios require you to replace the default, built-in icons of the Grid with Font Awesome icons.

To override the built-in styling of the Kendo UI Grid for Angular, replace the content of the elements which are responsible for the rendering of the respective icons. For example, to replace the expand or collapse detail row icons, use the following approach:

styles: [`
     .k-hierarchy-cell .k-plus::before {
       content: "\\f149";
       font-family: FontAwesome;
     }

     .k-hierarchy-cell .k-minus::before {
       content: "\\f148";
       font-family: FontAwesome;
     }

     // if used in SCSS, this can be reduced to
     // .k-hierarchy-cell .k-plus::before { @extends .fa-expand; }
 `]

The following example demonstrates how to implement Font Awesome icons in the Grid instead of the integrated font icons which are delivered by the Kendo UI suite for Angular.

import { Component, ViewChild, ViewEncapsulation, AfterViewInit, OnInit } from '@angular/core';
import { Observable } from 'rxjs';

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

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

import { CategoriesService } from './northwind.service';

@Component({
    providers: [CategoriesService],
    selector: 'my-app',
    template: `
      <kendo-grid
          [data]="view | async"
          [loading]="view.loading"
          [pageSize]="pageSize"
          [skip]="skip"
          [sortable]="true"
          [sort]="sort"
          [pageable]="true"
          [height]="550"
          (dataStateChange)="dataStateChange($event)"
        >
        <kendo-grid-column field="CategoryID" width="100"></kendo-grid-column>
        <kendo-grid-column field="CategoryName" width="200" title="Category Name"></kendo-grid-column>
        <kendo-grid-column field="Description" [sortable]="false">
        </kendo-grid-column>
        <div *kendoGridDetailTemplate="let dataItem">
            <category-details [category]="dataItem"></category-details>
        </div>
      </kendo-grid>
  `,
  encapsulation: ViewEncapsulation.None,
  styles: [`
    @import 'https://netdna.bootstrapcdn.com/font-awesome/3.2.1/css/font-awesome.css';

    .k-hierarchy-cell .k-plus::before {
      content: "\\f149";
      font-family: FontAwesome;
    }

    .k-hierarchy-cell .k-minus::before {
      content: "\\f148";
      font-family: FontAwesome;
    }

    // if used in SCSS, this can be reduced to
    // .k-hierarchy-cell .k-plus::before { @extends .fa-expand; }
  `]
})
export class AppComponent implements OnInit, AfterViewInit {
    public view: Observable<GridDataResult>;
    public sort: Array<SortDescriptor> = [];
    public pageSize = 10;
    public skip = 0;

    @ViewChild(GridComponent) grid: GridComponent;

    constructor(private service: CategoriesService) { }

    public ngOnInit(): void {
        // Bind directly to the service as it is a Subject
        this.view = this.service;

        // Fetch the data with the initial state
        this.loadData();
    }

    public dataStateChange({ skip, take, sort }: DataStateChangeEvent): void {
        // Save the current state of the Grid component
        this.skip = skip;
        this.pageSize = take;
        this.sort = sort;

        // Reload the data with the new state
        this.loadData();
    }

    public ngAfterViewInit(): void {
        // Expand the first row initially
        this.grid.expandRow(0);
    }

    private loadData(): void {
        this.service.query({ skip: this.skip, take: this.pageSize, sort: this.sort });
    }
}
import { Component, ViewChild, Input, OnInit } from '@angular/core';
import { Observable } from 'rxjs';
import { GridDataResult, GridComponent, PageChangeEvent } from '@progress/kendo-angular-grid';

import { ProductsService } from './northwind.service';

@Component({
    selector: 'category-details',
    providers: [ProductsService],
    template: `
      <kendo-grid
          [data]="view | async"
          [loading]="view.loading"
          [pageSize]="5"
          [skip]="skip"
          [pageable]="true"
          [scrollable]="'none'"
          (pageChange)="pageChange($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" format="{0:c}">
      </kendo-grid-column>
      </kendo-grid>
  `
})
export class CategoryDetailComponent implements OnInit {

    /**
     * The category for which details are displayed
     */
    @Input() public category: Object;

    private view: Observable<GridDataResult>;
    private skip = 0;

    constructor(private service: ProductsService) { }

    public ngOnInit(): void {
        this.view = this.service;

        /*load products for the given category*/
        this.service.queryForCategory(this.category, { skip: this.skip, take: 5 });
    }

    protected pageChange({ skip, take }: PageChangeEvent): void {
        this.skip = skip;
        this.service.queryForCategory(this.category, { skip, take });
    }
}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { GridDataResult } from '@progress/kendo-angular-grid';
import { toODataString } from '@progress/kendo-data-query';
import { Observable, BehaviorSubject } from 'rxjs';
import { map, tap } from 'rxjs/operators';

export abstract class NorthwindService extends BehaviorSubject<GridDataResult> {
    public loading: boolean;

    private BASE_URL = 'https://odatasampleservices.azurewebsites.net/V4/Northwind/Northwind.svc/';

    constructor(
        private http: HttpClient,
        protected tableName: string
    ) {
        super(null);
    }

    public query(state: any): void {
        this.fetch(this.tableName, state)
            .subscribe(x => super.next(x));
    }

    protected fetch(tableName: string, state: any): Observable<GridDataResult> {
        const queryStr = `${toODataString(state)}&$count=true`;
        this.loading = true;

        return this.http
            .get(`${this.BASE_URL}${tableName}?${queryStr}`)
            .pipe(
                map(response => (<GridDataResult>{
                    data: response['value'],
                    total: parseInt(response['@odata.count'], 10)
                })),
                tap(() => this.loading = false)
            );
    }
}

@Injectable()
export class ProductsService extends NorthwindService {
    constructor(http: HttpClient) { super(http, 'Products'); }

    public queryForCategory({ CategoryID }: { CategoryID: number }, state?: any): void {
        this.query(Object.assign({}, state, {
            filter: {
                filters: [{
                    field: 'CategoryID', operator: 'eq', value: CategoryID
                }],
                logic: 'and'
            }
        }));
    }

    public queryForProductName(ProductName: string, state?: any): void {
        this.query(Object.assign({}, state, {
            filter: {
                filters: [{
                    field: 'ProductName', operator: 'contains', value: ProductName
                }],
                logic: 'and'
            }
        }));
    }

}

@Injectable()
export class CategoriesService extends NorthwindService {
    constructor(http: HttpClient) { super(http, 'Categories'); }

    queryAll(st?: any): Observable<GridDataResult> {
        const state = Object.assign({}, st);
        delete state.skip;
        delete state.take;

        return this.fetch(this.tableName, state);
    }
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientModule } from '@angular/common/http';

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

import { AppComponent } from './app.component';

import { CategoryDetailComponent } from './category-details.component';

@NgModule({
  imports: [
    BrowserModule,
    BrowserAnimationsModule,
    HttpClientModule,
    GridModule
  ],
  declarations: [
    AppComponent,
    CategoryDetailComponent
  ],
  bootstrap: [
    AppComponent
  ]
})
export class AppModule { }
import { enableProdMode } from '@angular/core';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
import { AppModule } from './app.module';

enableProdMode();

const platform = platformBrowserDynamic();
platform.bootstrapModule(AppModule);

In this article