1

Here is my issue. I want to encapsulate the kendo angular component with my component. For example, the kendo-button component to be called my-button. What we are trying is to create our selectors so that even if we change kendo with some other library in the future it will not affect existing components in development as they will be using custom wrapper components. Of course, you create a wrapper component manually.

But is it possible to scaffold a library component automatically under our custom component or is it a possibility to change kendo or any other library component selector with our selector name. Looking for some tools or features that can help me achieve this.

3
  • not likely. I don't think such a thing exists. Every library is different. There is more to a component than just the selector. Commented Nov 5, 2019 at 4:50
  • Ya I agree there is more to the component then just selector. We have some component that we already encapsulate but that all is manual. That means all the events and possible inputs on kendo component has been duplicate on custom component it's very cumbersome and prone to errors or need alot of maintenance. Commented Nov 5, 2019 at 4:55
  • @Darksilence think of this way. How often do you change the libraries you use? As you said, it is too much work to encapsulate complex components. Use this time in case you need to change the library you use. As they say, "premature optimization is the root of all evil" Commented Nov 5, 2019 at 7:06

1 Answer 1

1

After moving from the PrimeNG component library to the Material library, having to manually re-implement each component instance, we had the exact same challenge. Moving forward, we wanted to de-couple the library components from the app as much as possible so that if ever we decided to change the library once again, it would be easier to replace.

The general idea is to create an app component that will act as a pass through component to a library component and all exposed functionality will be defined in an interface which the component implements.

A (rather) generic and simple example follows:

|-- Components
     |-- button
          |-- button.component.css
          |-- button.component.html
          |-- button.component.ts
          |-- button.model.ts
          |-- button.module.ts

The component files are the standard ones generated using the CLI. The .model.ts file contains the interface for the component and the .module.ts file contains an angular module also generated using the CLI.

button.component.html

<button (click)="clicked()"><i [ngClass]="icon"></i>{{text}}</button>

button.component.ts

import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
import { IButton } from './button.model';

@Component({
  selector: 'app-button',
  templateUrl: './button.component.html',
  styleUrls: ['./button.component.css']
})
export class ButtonComponent implements OnInit, IButton {

  @Input() text: string;
  @Input() icon: string;

  @Output() clickEvent: EventEmitter<void> = new EventEmitter<void>();

  constructor() { }

  ngOnInit() {
  }

  clicked(): void {
    this.clickEvent.emit();
  }

}

Define all of the inputs and outputs (as generically as possible) as an interface which the component (and any future implementation) will need to implement. This will make sure that the functionality of the component always remains the same.

button.model.ts

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

export interface IButton {
    text: string;
    icon: string;
    clickEvent: EventEmitter<void>;
}

Declare and Export the component in the module.

button.module.ts

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { ButtonComponent } from './button.component';

@NgModule({
  declarations: [
    ButtonComponent
  ],
  imports: [
    CommonModule,
    // component module imports here
  ],
  exports: [
    ButtonComponent
  ]
})
export class ButtonModule { }

Following the above method means that you only have to ever import the module to be able to reference the component in your app - you never directly reference the library component.

<app-button [text]="'export'" [icon]="'fas fa-file-export'" (clickEvent)="doSomething()"></app-button>

If ever you need to replace the component or extend it, make the necessary changes to the module (e.g. importing the library component module), the template and make sure that the component still implements the interface.

Sign up to request clarification or add additional context in comments.

1 Comment

That's a feasible solution for small components but most libraries have complex components with dozens of inputs and outputs. Having to redefine everything seems too cumbersome.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.