Reputation: 3428
I am using Kendo Ui as my favorite Ui Framework for Angular.
<kendo-multiselect [data]="listItems" [(ngModel)]="value">
<ng-template kendoMultiSelectHeaderTemplate let-dataItem>
<strong (click)="toggleSelection()">Alle Auswählen</strong>
</ng-template>
</kendo-multiselect>
So far so good, but I need the ng-template an more in nearly every of my multiselect dropdownlists. So my question is, can I create a directive which I can use directly on the host komponent which creates me the ng-template and all the other stuff I need or what is here the best solution to extend a existing component subtemplate.
example result:
<kendo-multiselect my-multiselectHeader
[data]="listItems"
[(ngModel)]="value">
</kendo-multiselect>
Upvotes: 2
Views: 2391
Reputation: 4159
Adding to squadwuschel's answer, this works perfect for me using Angular 8
I have extended Kendo MultiSelect component with Select All
functionality
In ngOnInit
the component is not yet rendered so you will get it as undefined. So you gotta use AfterViewInit
multiselect-extended.component.ts
import {
Component,
OnInit,
ViewChild,
Output,
ContentChild,
AfterViewInit,
EventEmitter
} from "@angular/core";
import {
HeaderTemplateDirective,
MultiSelectComponent
} from "@progress/kendo-angular-dropdowns";
@Component({
selector: "app-custom-multselect",
templateUrl: "./custom-multselect.component.html",
styleUrls: ["./custom-multselect.component.css"]
})
export class CustomMultselectComponent implements OnInit, AfterViewInit {
@ViewChild(HeaderTemplateDirective, { static: false })
headerTemplate: HeaderTemplateDirective;
@ContentChild(MultiSelectComponent, { static: false })
multiselect: MultiSelectComponent;
@Output() selectAllEvent: EventEmitter<boolean> = new EventEmitter();
constructor() {}
ngOnInit() {}
ngAfterViewInit() {
console.log(this.multiselect);
this.multiselect.headerTemplate = this.headerTemplate;
}
public toggleSelection(): void {
if (this.multiselect.value.length > 0) {
this.multiselect.reset();
this.selectAllEvent.emit(false);
} else {
this.multiselect.writeValue(this.multiselect.data);
this.multiselect.value = this.multiselect.data.slice();
this.selectAllEvent.emit(true);
}
}
}
Note that i have added a selectAllEvent
to update the checkboxes shown inside the multiselect dropdown.
app.component.html
<app-custom-multselect (selectAllEvent)=" selectAllItems($event)">
<kendo-multiselect [data]="listItems" [(ngModel)]="value" [textField]="'text'" [valueField]="'value'"
[autoClose]="false">
<ng-template kendoMultiSelectItemTemplate let-dataItem>
<input type="checkbox" class="k-checkbox"
[checked]="isItemSelected(dataItem.text) || isAllSelected">
<label class="k-checkbox-label">{{ dataItem.text }}</label>
</ng-template>
</kendo-multiselect>
</app-custom-multselect>
app.component.ts
export class AppComponent {
public listItems: Array<{ text: string; value: number }> = [
{ text: "Small", value: 1 },
{ text: "Medium", value: 2 },
{ text: "Large", value: 3 },
{ text: "XL", value: 4 },
{ text: "XXL", value: 5 }
];
public value: any = [];
public isAllSelected: boolean = false;
public isItemSelected(itemText: string): boolean {
return this.value.some(item => item.text === itemText);
}
selectAllItems(isSelectAll) {
if (isSelectAll) {
this.isAllSelected = true;
} else {
this.isAllSelected = false;
}
}
}
You can also find the demo here on StackBlitz
Upvotes: 0
Reputation: 3428
the Solution seems to be easier than I thought before.
I create a new surrounding directive where I can access the
with this solution I can access all natural properties from the original multiselect and I only extend the functions I "need" with the help from ng-content
sq-multiselect-extension.html:
<ng-template kendoMultiSelectHeaderTemplate let-dataItem>
<strong (click)="toggleSelection()" class="m-2 link-cursor">Alle Auswählen</strong>
</ng-template>
<ng-content></ng-content>
sq-multiselect-extension.ts:
import { Component, OnInit, ViewChild, ContentChild } from '@angular/core';
import { HeaderTemplateDirective, MultiSelectComponent } from '@progress/kendo-angular-dropdowns'
@Component({
selector: 'sq-multiselect-extension',
templateUrl: './sq-multiselect-extension.html',
})
export class SxpMultiselectComponent implements OnInit {
@ViewChild(HeaderTemplateDirective) headerTemplate: HeaderTemplateDirective;
@ContentChild(MultiSelectComponent) multiselect: MultiSelectComponent;
public ngOnInit() {
this.multiselect.headerTemplate = this.headerTemplate;
}
public toggleSelection(): void {
if (this.multiselect.value.length > 0) {
this.multiselect.reset();
}
else {
this.multiselect.writeValue(this.multiselect.data)
this.multiselect.value = this.multiselect.data.slice();
}
}
}
and to use this new component
<sq-multiselect-extension>
<kendo-multiselect [data]="listStringItems" [(ngModel)]="value" class="form-control">
</kendo-multiselect>
</sq-multiselect-extension>
Upvotes: 1
Reputation: 587
If you are planning to reuse the multiselect input, I would suggest wrapping the kendo element into a separate component. This way, if you will ever need to pass some custom options to the kendo element, you can do it in one place and it will affect all multiselects.
Upvotes: 0
Reputation: 2234
Yes, I think this isn't a big deal. It only depends on what you want to do but creating a directive to customize header doesn't seems to be too hard to do.
I think you can play with ng-template
injection and / or using of ngTemplateOutlet
.
But I suggest you to take a look at the kendoMultiSelectHeaderTemplate
directive to check what it does precisely.
If you're using the let-dataItem
variable, check you can use it anyway on your custom Directive
.
Upvotes: 0