All Components

Data Binding

The Menu enables you to bind it to an array of MenuItem objects by using its items property.

Each MenuItem may contain an items array of child items.

Binding to Local Data

The following example demonstrates how to bind the Menu to local data.

import { Component } from '@angular/core';
import { items } from './items';

@Component({
    selector: 'my-app',
    template: `
        <kendo-menu [items]="items">
        </kendo-menu>
    `
})
export class AppComponent {
    public items: any[] = items;
}
export const items: any[] = [{
    text: 'Item1',
    items: [{ text: 'Item1.1' }, { text: 'Item1.2', items: [{ text: 'Item1.2.1' }, { text: 'Item1.2.2' }] }]
}, {
    text: 'Item2',
    items: [{ text: 'Item2.1' }, { text: 'Item2.2' }, { text: 'Item2.3' }]
}, {
    text: 'Item3'
}];
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MenuModule } from '@progress/kendo-angular-menu';
import { HttpClientModule } from '@angular/common/http';

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

@NgModule({
  imports: [ BrowserModule, BrowserAnimationsModule, MenuModule, HttpClientModule ],
  declarations: [ AppComponent ],
  bootstrap: [ AppComponent ]
})

export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';

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

Binding to Remote Data

The following example demonstrates how to bind the Menu to remote data.

import { Component } from '@angular/core';
import { CategoriesService } from './categories.service';

@Component({
    providers: [CategoriesService],
    selector: 'my-app',
    template: `
        <kendo-menu [items]="items">
        </kendo-menu>
    `
})
export class AppComponent {
    public items: any[];

    constructor(categoriesService: CategoriesService) {
        categoriesService.fetchCategories().subscribe(categories => {
            this.items = this.mapItems(categories, ['CategoryName', 'ProductName'], ['Products']);
        });
    }

    // convert the received data to menu items.
    private mapItems(items: any[], textFields: string[], childFields: string[], level: number = 0): any[] {
        const childField = childFields[level];
        const textField = textFields[level];

        return items.map(item => {
            const result: any = {
                text: item[textField]
            };
            // convert the children data to menu items.
            if (childField && item[childField]) {
                result.items = this.mapItems(item[childField], textFields, childFields, level + 1);
            }

            return result;
        });
    }
}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

import { map } from 'rxjs/operators/map';

@Injectable()
export class CategoriesService {

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

    constructor(private http: HttpClient) { }

    public fetchCategories(): Observable<any[]> {
        return this.fetch(`${this.BASE_URL}/Categories?$expand=Products`);
    }

    private fetch(url: string): Observable<any[]> {
        return this.http
            .get(url)
            .pipe(map((response: any) => response.value));
    }
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MenuModule } from '@progress/kendo-angular-menu';
import { HttpClientModule } from '@angular/common/http';

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

@NgModule({
  imports: [ BrowserModule, BrowserAnimationsModule, MenuModule, HttpClientModule ],
  declarations: [ AppComponent ],
  bootstrap: [ AppComponent ]
})

export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';

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

Built-in Directives

To simplify data binding and minimize boilerplate code, the Menu delivers the following built-in directives:

  • kendoMenuHierarchyBinding—Handles the conversion to array of MenuItems of hierarchical data.
  • kendoMenuFlatBinding—Handles the conversion to array of MenuItems of flat data.

Hierarchy Binding

The kendoMenuHierarchyBinding directive simplifies the binding to hierarchical data. To use it, bind the directive to the data and set the childrenField, textField, etc. properties to the fields from the data that should be used to create the MenuItems. If a property is set to a array of fields, each hierarchical level uses the field that corresponds to the same index in the array, or the last item in the array. If a property is set to a field then it will be used for all levels.

The following example demonstrates using the kendoMenuHierarchyBinding directive.

import { Component } from '@angular/core';
import { CategoriesService } from './categories.service';

@Component({
    providers: [CategoriesService],
    selector: 'my-app',
    template: `
        <kendo-menu [kendoMenuHierarchyBinding]="categories" [textField]="['CategoryName', 'ProductName']" childrenField="Products">
        </kendo-menu>
    `
})
export class AppComponent {
    public categories: any[];

    constructor(categoriesService: CategoriesService) {
        categoriesService.fetchCategories().subscribe(categories => {
            this.categories = categories;
        });
    }
}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

import { map } from 'rxjs/operators/map';

@Injectable()
export class CategoriesService {

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

    constructor(private http: HttpClient) { }

    public fetchCategories(): Observable<any[]> {
        return this.fetch(`${this.BASE_URL}/Categories?$expand=Products`);
    }

    private fetch(url: string): Observable<any[]> {
        return this.http
            .get(url)
            .pipe(map((response: any) => response.value));
    }
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MenuModule } from '@progress/kendo-angular-menu';
import { HttpClientModule } from '@angular/common/http';

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

@NgModule({
  imports: [ BrowserModule, BrowserAnimationsModule, MenuModule, HttpClientModule ],
  declarations: [ AppComponent ],
  bootstrap: [ AppComponent ]
})

export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';

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

Flat Binding

The kendoMenuFlatBinding directive simplifies the binding to flat data. To use it, bind the directive to the data and set the idField and parentIdField to the fields from the data that represent the relation between parent and child nodes.

The following example demonstrates using the kendoMenuFlatBinding directive.

import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
        <kendo-menu [kendoMenuFlatBinding]="flatData"
            idField="id"
            parentIdField="parentId"
            textField="name"
            iconField="iconName">
        </kendo-menu>
    `
})
export class AppComponent {
    public flatData: any[] = [{
        name: 'Item1',
        iconName: 'folder',
        id: 1
    }, {
        name: 'Item1.1',
        iconName: 'image',
        id: 2,
        parentId: 1
    }, {
        name: 'Item1.2',
        iconName: 'folder',
        id: 3,
        parentId: 1
    }, , {
        name: 'Item1.2.1',
        id: 4,
        parentId: 3,
        iconName: 'pdf'
    }];
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MenuModule } from '@progress/kendo-angular-menu';
import { HttpClientModule } from '@angular/common/http';

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

@NgModule({
  imports: [ BrowserModule, BrowserAnimationsModule, MenuModule, HttpClientModule ],
  declarations: [ AppComponent ],
  bootstrap: [ AppComponent ]
})

export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';

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

Updating the binding directives

If individual fields or items are modified, Angular will not detect a change for the data and the Menu will not be updated. In this case you can update the Menu by using the directives rebind method.

The following example demonstrates updating the Menu after modifying the data.

import { Component, ViewChild } from '@angular/core';
import { CategoriesService } from './categories.service';
import { HierarchyBindingDirective } from '@progress/kendo-angular-menu';

@Component({
    providers: [CategoriesService],
    selector: 'my-app',
    template: `
        <kendo-menu [kendoMenuHierarchyBinding]="categories" [textField]="['CategoryName', 'ProductName']" childrenField="Products" #hierarchy="kendoMenuHierarchyBinding">
        </kendo-menu>
        <ul style="list-style: none;">
            <li *ngFor="let category of categories; let index = index;">
                {{ category.CategoryName }}
                <span class="k-icon k-i-close" (click)="remove(index)"></span>
            </li>
        </ul>
    `
})
export class AppComponent {
    @ViewChild('hierarchy')
    public hierarchy: HierarchyBindingDirective;

    public categories: any[];

    constructor(categoriesService: CategoriesService) {
        categoriesService.fetchCategories().subscribe(categories => {
            this.categories = categories;
        });
    }

    public remove(index: number): void {
        this.categories.splice(index, 1);
        this.hierarchy.rebind();
    }
}
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { Observable } from 'rxjs/Observable';

import { map } from 'rxjs/operators/map';

@Injectable()
export class CategoriesService {

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

    constructor(private http: HttpClient) { }

    public fetchCategories(): Observable<any[]> {
        return this.fetch(`${this.BASE_URL}/Categories?$expand=Products`);
    }

    private fetch(url: string): Observable<any[]> {
        return this.http
            .get(url)
            .pipe(map((response: any) => response.value));
    }
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { MenuModule } from '@progress/kendo-angular-menu';
import { HttpClientModule } from '@angular/common/http';

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

@NgModule({
  imports: [ BrowserModule, BrowserAnimationsModule, MenuModule, HttpClientModule ],
  declarations: [ AppComponent ],
  bootstrap: [ AppComponent ]
})

export class AppModule { }
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

import { AppModule } from './app.module';

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

In this article