squadwuschel
squadwuschel

Reputation: 3428

extend a angular component with ng-template

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

Answers (4)

HariHaran
HariHaran

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

squadwuschel
squadwuschel

Reputation: 3428

the Solution seems to be easier than I thought before.

I create a new surrounding directive where I can access the

  • ContentChild => is the multiselect component where we have access to all properties
  • ViewChild => is the Headertemplate I want to assign to the multiselect

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

Lucian Moldovan
Lucian Moldovan

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

Maxime
Maxime

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

Related Questions