Custom Control Types

The ToolBar provides options for creating custom tools. These could be added to the Toolbar and Overflow Popup. Keyboard navigation can also be applied.

import {
    Component,
    Input,
    TemplateRef,
    ViewChild,
    ElementRef,
    OnInit,
    forwardRef
} from '@angular/core';
import { ToolBarToolComponent } from '@progress/kendo-angular-toolbar';
import { DropDownListComponent } from '@progress/kendo-angular-dropdowns';

@Component({
    providers: [{ provide: ToolBarToolComponent, useExisting: forwardRef(() => CustomToolComponent) }],
    selector: 'custom-tool',
    template: `
        <ng-template #toolbarTemplate>
            <span #toolbarElement>
                {{ text }}
                <kendo-dropdownlist
                    #dropdownlist
                    [tabindex]="tabindex"
                    [(value)]="value"
                    [data]="items"
                    [defaultItem]="'Select sport...'"
                    [itemDisabled]="itemDisabled"
                >
                </kendo-dropdownlist>
            </span>
        </ng-template>
        <ng-template #popupTemplate>
            <span #popupElement>
                <button kendoButton #button [tabindex]="tabindex" [icon]="'heart'" (click)="opened = true">Fav Sport</button>
            </span>

            <kendo-dialog title="Select a favourite sport" *ngIf="opened" (close)="opened = false">
                <kendo-dropdownlist [(value)]="value" [data]="items" [defaultItem]="'Select sport...'"> </kendo-dropdownlist>
                <kendo-dialog-actions>
                    <button kendoButton (click)="opened = false">Ok</button>
                </kendo-dialog-actions>
            </kendo-dialog>
        </ng-template>
    `
})
export class CustomToolComponent extends ToolBarToolComponent implements OnInit {
    @Input() public text: string;

    @ViewChild('toolbarTemplate', { static: true }) public toolbarTemplate: TemplateRef<any>;
    @ViewChild('toolbarElement', { static: false }) public toolbarElement: ElementRef;

    @ViewChild('popupTemplate', { static: true }) public popupTemplate: TemplateRef<any>;
    @ViewChild('popupElement', { static: false }) public popupElement: ElementRef;

    @ViewChild('dropdownlist', { read: DropDownListComponent, static: false }) public dropdownlist: DropDownListComponent;
    @ViewChild('button', { static: false }) public button: ElementRef;

    public value: string;
    public items: Array<string> = ['Badminton', 'Tennis', 'Squash'];
    public opened = false;
    public tabindex = -1;
    public itemDisabled: (itemArgs: { dataItem: any; index: number }) => boolean;

    constructor() {
        super();
    }

    public ngOnInit(): void {
        this.itemDisabled = (itemArgs: { dataItem: any; index: number }) =>
            !this.overflows && this.dropdownlist && !this.dropdownlist.isOpen;
    }

    public canFocus(): boolean {
        return true; // marks the tools as focusable
    }

    public focus(): void {
        // manage the roving tabindex
        // see https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex
        this.tabindex = 0;
        if (this.overflows) {
            // focus the button in the overflowTemplate
            this.button.nativeElement.focus();
        } else {
            // focus the DropDownList in the toolbarTemplate
            this.dropdownlist.focus();
        }
    }

    public handleKey(): boolean {
        // manage the roving tabindex
        // see https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex
        this.tabindex = -1;
        // tell the toolbar that the focus can move to the next/prev focusable tool
        return false;
    }
}
import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
    <input
        #range
        style="width: 100%; display: block;"
        type="range"
        value="100"
        min="0"
        max="100"
        step="1"
        (input)="toolbarWidth = range.value"
    />
    <kendo-toolbar [overflow]="true" [style.width.%]="toolbarWidth">
        <custom-tool [text]="'Favourite sport'"></custom-tool>
        <kendo-toolbar-button [text]="'My button'"></kendo-toolbar-button>
        <kendo-toolbar-button [text]="'Toggle'" [toggleable]="true"></kendo-toolbar-button>
        <kendo-toolbar-splitbutton
            [text]="'Split Button'"
            [data]="splitButtonData">
        </kendo-toolbar-splitbutton>
    </kendo-toolbar>
  `
})

export class AppComponent {
    public splitButtonData: Array<any> = [{
        text: 'Option 1'
    }, {
        text: 'Option 2',
    }, {
        text: 'Option 3',
    }];
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientModule, HttpClientJsonpModule } from '@angular/common/http';

import { ToolBarModule } from '@progress/kendo-angular-toolbar';
import { DropDownListModule } from '@progress/kendo-angular-dropdowns';
import { ButtonsModule } from '@progress/kendo-angular-buttons';
import { DialogModule } from '@progress/kendo-angular-dialog';
import { CustomToolComponent } from './custom-tool.component';

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

@NgModule({
    imports: [
        BrowserModule,
        BrowserAnimationsModule,
        HttpClientModule,
        HttpClientJsonpModule,
        ToolBarModule,
        ButtonsModule,
        DialogModule,
        DropDownListModule
    ],
    declarations: [
        AppComponent,
        CustomToolComponent
    ],
    bootstrap: [
        AppComponent
    ]
})
export class AppModule { }
import { AppModule } from './app.module';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

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

Adding Custom Tool to the ToolBar

In order to achieve this, follow the steps below:

import { Component } from '@angular/core';
import { ToolBarToolComponent } from '@progress/kendo-angular-toolbar';

@Component({
    providers: [{ provide: ToolBarToolComponent, useExisting: forwardRef(() => CustomToolComponent) }],
    selector: 'custom-tool',
})

export class CustomToolComponent extends ToolBarToolComponent {

  constructor() {
        super();
    }
}
  • Create a template using <ng-template> and get a reference to it by using a template reference variable. This template is used by the toolbar for the custom tool rendering.

    Please note that the class field holding the reference to the template has to be named toolbarTemplate.

import {
    Component,
    TemplateRef,
    ViewChild,
    forwardRef
} from '@angular/core';
import { ToolBarToolComponent } from '@progress/kendo-angular-toolbar';
import { DropDownListComponent } from '@progress/kendo-angular-dropdowns';

@Component({
    providers: [{ provide: ToolBarToolComponent, useExisting: forwardRef(() => CustomToolComponent) }],
    selector: 'custom-tool',
    template: `
        <ng-template #toolbarTemplate>
            {{ text }}
            <kendo-dropdownlist></kendo-dropdownlist>
        </ng-template>
    `
})
export class CustomToolComponent extends ToolBarToolComponent {
    public tabindex = -1;

    @ViewChild('toolbarTemplate', { static: true }) public toolbarTemplate: TemplateRef<any>;

    constructor() {
        super();
    }
}
  • Add the rest of the required custom tool functionality and include the tool in the ToolBar.
import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
    <h4>Resize the output frame to see responsive behavior</h4>

    <kendo-toolbar [overflow]="true">
        <custom-tool
            [text]="'Favourite sport'"
            [items]="dataItems"
            ></custom-tool>
        <kendo-toolbar-button [text]="'My button'"></kendo-toolbar-button>
        <kendo-toolbar-button [text]="'Toggle'" [toggleable]="true"></kendo-toolbar-button>
        <kendo-toolbar-splitbutton
            [text]="'Split Button'"
            [data]="splitButtonData">
        </kendo-toolbar-splitbutton>
    </kendo-toolbar>
  `
})

export class AppComponent {
    public dataItems: Array<string> = ['Basketball', 'Rugby', 'Baseball'];

    public splitButtonData: Array<any> = [{
        text: 'Option 1'
    }, {
        text: 'Option 2',
    }, {
        text: 'Option 3',
    }];
}
import {
    Component,
    Input,
    Output,
    EventEmitter,
    TemplateRef,
    ViewChild,
    forwardRef
} from '@angular/core';
import { ToolBarToolComponent } from '@progress/kendo-angular-toolbar';
import { DropDownListComponent } from '@progress/kendo-angular-dropdowns';

@Component({
    providers: [{ provide: ToolBarToolComponent, useExisting: forwardRef(() => CustomToolComponent) }],
    selector: 'custom-tool',
    template: `
        <ng-template #toolbarTemplate>
            {{ text }}
            <kendo-dropdownlist
                [tabindex]="tabindex"
                [(value)]="value"
                [data]="items"
                [defaultItem]="defaultItem"
                [itemDisabled]="itemDisabled"
                [disabled]="disabled"
                (selectionChange)="selectionChangeEvent.emit($event)"
            >
            </kendo-dropdownlist>
        </ng-template>
    `
})
export class CustomToolComponent extends ToolBarToolComponent {
    public tabindex = -1;

    @Input() public text: string;
    @Input() public items: Array<string>;
    @Input() public value: string;
    @Input() public defaultItem: string;
    @Input() public itemDisabled: (itemArgs: { dataItem: any; index: number }) => boolean;
    @Input() public disabled: boolean;
    @Output() public selectionChangeEvent = new EventEmitter();

    @ViewChild('toolbarTemplate', { static: true }) public toolbarTemplate: TemplateRef<any>;

    constructor() {
        super();
    }
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientModule, HttpClientJsonpModule } from '@angular/common/http';

import { ToolBarModule } from '@progress/kendo-angular-toolbar';
import { DropDownListModule } from '@progress/kendo-angular-dropdowns';
import { ButtonsModule } from '@progress/kendo-angular-buttons';
import { DialogModule } from '@progress/kendo-angular-dialog';
import { CustomToolComponent } from './custom-tool.component';

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

@NgModule({
    imports: [
        BrowserModule,
        BrowserAnimationsModule,
        HttpClientModule,
        HttpClientJsonpModule,
        ToolBarModule,
        ButtonsModule,
        DialogModule,
        DropDownListModule
    ],
    declarations: [
        AppComponent,
        CustomToolComponent
    ],
    bootstrap: [
        AppComponent
    ]
})
export class AppModule { }
import { AppModule } from './app.module';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

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

Adding Custom Tool to the Overflow Popup

The Toolbar provides options for adding tools to the Overflow Popup. This is especially useful when there is insufficient ToolBar width to display all tools.

To add a tool to the Overflow Popup, create a template using <ng-template> and get a reference to it by using a template reference variable. It is used by the toolbar for rendering the custom tool inside the overflow popup.

Please note that the class field holding the reference to the template has to be named popupTemplate.

import {
    Component,
    Input,
    Output,
    EventEmitter,
    TemplateRef,
    ViewChild,
    ElementRef,
    forwardRef
} from '@angular/core';
import { ToolBarToolComponent } from '@progress/kendo-angular-toolbar';
import { DropDownListComponent } from '@progress/kendo-angular-dropdowns';

@Component({
    providers: [{ provide: ToolBarToolComponent, useExisting: forwardRef(() => CustomToolComponent) }],
    selector: 'custom-tool',
    template: `
        <ng-template #toolbarTemplate>
           {{ text }}
           <kendo-dropdownlist
               [tabindex]="tabindex"
               [(value)]="value"
               [data]="items"
               [defaultItem]="defaultItem"
               [itemDisabled]="itemDisabled"
               [disabled]="disabled"
               (selectionChange)="selectionChangeEvent.emit($event)"
           >
           </kendo-dropdownlist>
        </ng-template>
        <ng-template #popupTemplate>
            <button
                style="width: 100%"
                kendoButton
                [tabindex]="tabindex"
                [icon]="'heart'"
                [disabled]="disabled"
                (click)="opened = true"
            >
                {{ text }}
            </button>

            <kendo-dialog title="Select a favourite sport" *ngIf="opened" (close)="opened = false">
               <kendo-dropdownlist
                   [tabindex]="tabindex"
                   [(value)]="value"
                   [data]="items"
                   [defaultItem]="defaultItem"
                   [itemDisabled]="itemDisabled"
                   [disabled]="disabled"
                   (selectionChange)="selectionChangeEvent.emit($event)"
               >
               </kendo-dropdownlist>
               <kendo-dialog-actions>
                   <button kendoButton (click)="opened = false">Ok</button>
               </kendo-dialog-actions>
            </kendo-dialog>
        </ng-template>
    `
})
export class CustomToolComponent extends ToolBarToolComponent {
    public tabindex = -1;

    @Input() public text: string;
    @Input() public items: Array<string>;
    @Input() public value: string;
    @Input() public defaultItem: string;
    @Input() public itemDisabled: (itemArgs: { dataItem: any; index: number }) => boolean;
    @Input() public disabled: boolean;
    @Output() public selectionChangeEvent = new EventEmitter();

    @ViewChild('toolbarTemplate', { static: true }) public toolbarTemplate: TemplateRef<any>;

    @ViewChild('popupTemplate', { static: true }) public popupTemplate: TemplateRef<any>;

    public opened = false;

    constructor() {
        super();
    }
}
import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
    <h4>Resize the output frame to see responsive behavior</h4>

    <kendo-toolbar [overflow]="true">
        <custom-tool
            [text]="'Favourite sport'"
            [items]="dataItems"
            ></custom-tool>
        <kendo-toolbar-button [text]="'My button'"></kendo-toolbar-button>
        <kendo-toolbar-button [text]="'Toggle'" [toggleable]="true"></kendo-toolbar-button>
        <kendo-toolbar-splitbutton
            [text]="'Split Button'"
            [data]="splitButtonData">
        </kendo-toolbar-splitbutton>
    </kendo-toolbar>
  `
})

export class AppComponent {
    public dataItems: Array<string> = ['Basketball', 'Rugby', 'Baseball'];

    public splitButtonData: Array<any> = [{
        text: 'Option 1'
    }, {
        text: 'Option 2',
    }, {
        text: 'Option 3',
    }];
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientModule, HttpClientJsonpModule } from '@angular/common/http';

import { ToolBarModule } from '@progress/kendo-angular-toolbar';
import { DropDownListModule } from '@progress/kendo-angular-dropdowns';
import { ButtonsModule } from '@progress/kendo-angular-buttons';
import { DialogModule } from '@progress/kendo-angular-dialog';
import { CustomToolComponent } from './custom-tool.component';

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

@NgModule({
    imports: [
        BrowserModule,
        BrowserAnimationsModule,
        HttpClientModule,
        HttpClientJsonpModule,
        ToolBarModule,
        ButtonsModule,
        DialogModule,
        DropDownListModule
    ],
    declarations: [
        AppComponent,
        CustomToolComponent
    ],
    bootstrap: [
        AppComponent
    ]
})
export class AppModule { }
import { AppModule } from './app.module';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

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

Adding Keyboard Navigation

This section represents a guide for implementing keyboard navigation. This step is optional and is entirely up to the developer, whether it would be added.

The following three methods should be added in order to implement keyboard navigation. If these methods are not implemented, the tool will be skipped when using the arrow keys for navigation.

  • canFocus - Determines whether the tool can be focused. If the returned value is false, the tool will not be part of the keyboard navigation.
  • focus - Called when the tool is being focused using keyboard navigation or mouse click.
  • handleKey - Returns boolean value, which determines whether the ToolBar will move the focus to the next/previous tool. The method is called when the tool is focused and one of the arrow keys is pressed (Left or Right arrow when the tool is inside the toolbar, Up or Down arrow when the tool is inside the overflow popup). If the return value is true, the ToolBar will not move the focus to the next/previous tool, which is usually required when the internal keyboard navigation of the underlying component is using the arrow keys. If the handleKey() returns false, the ToolBar will move the focus to the next/previous tool.
import {
    Component,
    Input,
    TemplateRef,
    ViewChild,
    ElementRef,
    OnInit,
    forwardRef
} from '@angular/core';
import { ToolBarToolComponent } from '@progress/kendo-angular-toolbar';
import { DropDownListComponent } from '@progress/kendo-angular-dropdowns';

@Component({
    providers: [{ provide: ToolBarToolComponent, useExisting: forwardRef(() => CustomToolComponent) }],
    selector: 'custom-tool',
    template: `
        <ng-template #toolbarTemplate>
            <span #toolbarElement>
                {{ text }}
                <kendo-dropdownlist
                    #dropdownlist
                    [tabindex]="tabindex"
                    [(value)]="value"
                    [data]="items"
                    [defaultItem]="'Select sport...'"
                    [itemDisabled]="itemDisabled"
                >
                </kendo-dropdownlist>
            </span>
        </ng-template>
        <ng-template #popupTemplate>
            <span #popupElement>
                <button kendoButton #button [tabindex]="tabindex" [icon]="'heart'" (click)="opened = true">Fav Sport</button>
            </span>

            <kendo-dialog title="Select a favourite sport" *ngIf="opened" (close)="opened = false">
                <kendo-dropdownlist [(value)]="value" [data]="items" [defaultItem]="'Select sport...'"> </kendo-dropdownlist>
                <kendo-dialog-actions>
                    <button kendoButton (click)="opened = false">Ok</button>
                </kendo-dialog-actions>
            </kendo-dialog>
        </ng-template>
    `
})
export class CustomToolComponent extends ToolBarToolComponent implements OnInit {
    @Input() public text: string;

    @ViewChild('toolbarTemplate', { static: true }) public toolbarTemplate: TemplateRef<any>;
    @ViewChild('toolbarElement', { static: false }) public toolbarElement: ElementRef;

    @ViewChild('popupTemplate', { static: true }) public popupTemplate: TemplateRef<any>;
    @ViewChild('popupElement', { static: false }) public popupElement: ElementRef;

    @ViewChild('dropdownlist', { read: DropDownListComponent, static: false }) public dropdownlist: DropDownListComponent;
    @ViewChild('button', { static: false }) public button: ElementRef;

    public value: string;
    public items: Array<string> = ['Badminton', 'Tennis', 'Squash'];
    public opened = false;
    public tabindex = -1;
    public itemDisabled: (itemArgs: { dataItem: any; index: number }) => boolean;

    constructor() {
        super();
    }

    public ngOnInit(): void {
        this.itemDisabled = (itemArgs: { dataItem: any; index: number }) =>
            !this.overflows && this.dropdownlist && !this.dropdownlist.isOpen;
    }

    public canFocus(): boolean {
        return true; // marks the tools as focusable
    }

    public focus(): void {
        // manage the roving tabindex
        // see https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex
        this.tabindex = 0;
        if (this.overflows) {
            // focus the button in the overflowTemplate
            this.button.nativeElement.focus();
        } else {
            // focus the DropDownList in the toolbarTemplate
            this.dropdownlist.focus();
        }
    }

    public handleKey(): boolean {
        // manage the roving tabindex
        // see https://www.w3.org/TR/wai-aria-practices/#kbd_roving_tabindex
        this.tabindex = -1;
        // tell the toolbar that the focus can move to the next/prev focusable tool
        return false;
    }
}
import { Component } from '@angular/core';

@Component({
    selector: 'my-app',
    template: `
    <input
        #range
        style="width: 100%; display: block;"
        type="range"
        value="100"
        min="0"
        max="100"
        step="1"
        (input)="toolbarWidth = range.value"
    />
    <kendo-toolbar [overflow]="true" [style.width.%]="toolbarWidth">
        <custom-tool [text]="'Favourite sport'"></custom-tool>
        <kendo-toolbar-button [text]="'My button'"></kendo-toolbar-button>
        <kendo-toolbar-button [text]="'Toggle'" [toggleable]="true"></kendo-toolbar-button>
        <kendo-toolbar-splitbutton
            [text]="'Split Button'"
            [data]="splitButtonData">
        </kendo-toolbar-splitbutton>
    </kendo-toolbar>
  `
})

export class AppComponent {
    public splitButtonData: Array<any> = [{
        text: 'Option 1'
    }, {
        text: 'Option 2',
    }, {
        text: 'Option 3',
    }];
}
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { HttpClientModule, HttpClientJsonpModule } from '@angular/common/http';

import { ToolBarModule } from '@progress/kendo-angular-toolbar';
import { DropDownListModule } from '@progress/kendo-angular-dropdowns';
import { ButtonsModule } from '@progress/kendo-angular-buttons';
import { DialogModule } from '@progress/kendo-angular-dialog';
import { CustomToolComponent } from './custom-tool.component';

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

@NgModule({
    imports: [
        BrowserModule,
        BrowserAnimationsModule,
        HttpClientModule,
        HttpClientJsonpModule,
        ToolBarModule,
        ButtonsModule,
        DialogModule,
        DropDownListModule
    ],
    declarations: [
        AppComponent,
        CustomToolComponent
    ],
    bootstrap: [
        AppComponent
    ]
})
export class AppModule { }
import { AppModule } from './app.module';
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';

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

In this article