Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Override/extend third-party component's template

I am currently importing a third party component. For my use case I need to override that specific component template.

Since this is a third party component, and imported via npm package, I don't want to change the component so I don't have to update it everytime the package is updated.

Is there any way to overwrite the template of another component?

I know you can use <ng-content> if you want to inject some element. But here is not viable.

The html is something like this:

<third-party-component [items]="items" [example]="example">

The controller is something like this:

import {THIRD_PARTY_DIRECTIVES} from 'ng2-select/ng2-select';

@Component({
  selector: 'example-component',
  directives: [THIRD_PARTY_DIRECTIVES]
})
export class Example {

  private items: Array<string> = [
    'whatever', 'whatever2', 'whatever3'
  ];
}

Is there any way I can specify the template I want for <third-party-component> without editing that specific component declaration? Or even extend it only ?

like image 619
Joel Almeida Avatar asked Jan 26 '16 16:01

Joel Almeida


2 Answers

After playing around with it. A simple extend will work for my use case.

Basically I created a class that extends the thirdPartyClass.

What happens here is that I am overwriting the template for the thirdPartyClass by creating my own selector and importing only the class.

Something like this:

import {component} from 'angular2/core';
import {thirdPartyClass} from 'example/example';

@Component({
  selector: 'my-selector',
  template: '<div>my template</div>'
})

export class MyOwnComponent extends thirdPartyClass {
  constructor() {
     super()
  }
}

Notes:

  • If you are using this method, don't forget to import any pipes that are used in the thirdPartyClass template.
  • If the functionality is updated in the thirdPartyClass that depends upon the template, you'll need to update by hand.
  • I prefered this solution to refering to the ReflectMetaData because its a simple extend instead of accessing the annotations and force changing it.
like image 179
Joel Almeida Avatar answered Nov 22 '22 14:11

Joel Almeida


You can use Reflect to change metadata of component. Here's the super simple example:

import {Component} from 'angular2/core'

@Component({
  selector: 'thing',
  template: `Hi!`,
})
export class Thing {}

annotations = Reflect.getMetadata('annotations', Thing);
for (let i = 0; i < annotations.length; i += 1) {
  if (annotations[i].constructor.name === 'ComponentMetadata') {
    annotations[i].template = 'Ho!';
    break;
  }
}

@Component({
  selector: 'my-app',
  directives: [Thing],
  template: `<thing></thing>`,
})
export class App {}

Just make sure you update template before injecting it into parent component. Also check which metadata you need to access, might be DirectiveMetadata in your case.

like image 43
Sasxa Avatar answered Nov 22 '22 13:11

Sasxa