ng-dynamic-component

Dynamic components with full life-cycle support for inputs and outputs for Angular

Github星跟蹤圖

ng-dynamic-component

Dynamic components with full life-cycle support for inputs and outputs

Travis CI
Appveyor
Coverage
Maintainability
Npm
Npm Downloads
Licence
semantic-release
Greenkeeper badge, Angular, ng-dynamic-component, NPM package, -------, --------------------, -----------------------------, 9.x.x, 6.x.x, ng-dynamic-component@^6.0.0, 8.x.x, 5.x.x, ng-dynamic-component@^5.0.0, 7.x.x, 4.x.x, ng-dynamic-component@^4.0.0, 6.x.x, 3.x.x, ng-dynamic-component@^3.0.0, 5.x.x, 2.x.x, ng-dynamic-component@^2.0.0, 4.x.x, 1.x.x, ng-dynamic-component@^1.0.0, 2.x.x, 0.x.x, ng-dynamic-component@^0.0.0, ## Installation

$ npm install ng-dynamic-component --save

Usage

Root import

Import DynamicModule once in your root module (usually AppModule):

import { DynamicModule } from 'ng-dynamic-component';

@NgModule({
  imports: [DynamicModule.forRoot()],
})
export class AppModule {}

Usage import

And then you may import the module in any other of your modules where you need
to render dynamic components:

import { DynamicModule } from 'ng-dynamic-component';

@NgModule({
  imports: [DynamicModule],
})
export class OtherModule {}

DynamicComponent

Then in your component's template include <ndc-dynamic> where you want to render component
and bind from your component class type of component to render:

@Component({
  selector: 'my-component',
  template: `
    <ndc-dynamic [ndcDynamicComponent]="component"></ndc-dynamic>
  `,
})
class MyComponent {
  component = Math.random() > 0.5 ? MyDynamicComponent1 : MyDynamicComponent2;
}

Inputs and Outputs

You can also pass inputs and outputs to your dynamic components:

@Component({
  selector: 'my-component',
  template: `
    <ndc-dynamic
      [ndcDynamicComponent]="component"
      [ndcDynamicInputs]="inputs"
      [ndcDynamicOutputs]="outputs"
    ></ndc-dynamic>
  `,
})
class MyComponent {
  component = MyDynamicComponent1;
  inputs = {
    hello: 'world',
    something: () => 'can be really complex',
  };
  outputs = {
    onSomething: type => alert(type),
  };
}

@Component({
  selector: 'my-dynamic-component1',
  template: 'Dynamic Component 1',
})
class MyDynamicComponent1 {
  @Input()
  hello: string;
  @Input()
  something: Function;
  @Output()
  onSomething = new EventEmitter<string>();
}

Here you can update your inputs (ex. inputs.hello = 'WORLD') and they will trigger standard Angular's life-cycle hooks
(of course you should consider which change detection strategy you are using).

Component Creation Events

You can subscribe to component creation events, being passed a reference to the ComponentRef:

@Component({
  selector: 'my-component',
  template: `
    <ndc-dynamic
      [ndcDynamicComponent]="component"
      (ndcDynamicCreated)="componentCreated($event)"
    ></ndc-dynamic>
  `,
})
class MyComponent {
  component = MyDynamicComponent1;
  componentCreated(compRef: ComponentRef<any>) {
    // utilize compRef in some way ...
  }
}

Attributes

Since v2.2.0 you can now declaratively set attributes, as you would inputs, via ndcDynamicAttributes:

import { AttributesMap } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `
    <ndc-dynamic
      [ndcDynamicComponent]="component"
      [ndcDynamicAttributes]="attrs"
    ></ndc-dynamic>
  `,
})
class MyComponent {
  component = MyDynamicComponent1;
  attrs: AttributesMap = {
    'my-attribute': 'attribute-value',
    class: 'some classes',
  };
}

Remember that attributes values are always strings (while inputs can be any value).
So to have better type safety you can use AttributesMap interface for your attributes maps.

Also you can use ngComponentOutlet and ndcDynamicAttributes with * syntax:

import { AttributesMap } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `
    <ng-container
      *ngComponentOutlet="component; ndcDynamicAttributes: attrs"
    ></ng-container>
  `,
})
class MyComponent {
  component = MyDynamicComponent1;
  attrs: AttributesMap = {
    'my-attribute': 'attribute-value',
    class: 'some classes',
  };
}

Directives (experimental)

Since v3.1.0 you can now declaratively set directives, via ndcDynamicDirectives:

NOTE: In dynamic directives queries like @ContentChild and host decorators like @HostBinding
will not work due to involved complexity required to handle it (but PRs are welcome!).

import { dynamicDirectiveDef } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `
    <ng-container
      [ngComponentOutlet]="component"
      [ndcDynamicDirectives]="dirs"
    ></ng-container>
  `,
})
class MyComponent {
  component = MyDynamicComponent1;
  dirs = [dynamicDirectiveDef(MyDirective)];
}

It's also possible to bind inputs and outputs to every dynamic directive:

import { dynamicDirectiveDef } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `
    <ng-container
      [ngComponentOutlet]="component"
      [ndcDynamicDirectives]="dirs"
    ></ng-container>
  `,
})
class MyComponent {
  component = MyDynamicComponent1;
  directiveInputs = { prop1: 'value' };
  directiveOutputs = { output1: evt => this.doSomeStuff(evt) };
  dirs = [
    dynamicDirectiveDef(
      MyDirective,
      this.directiveInputs,
      this.directiveOutputs,
    ),
  ];
}

To change inputs, just update the object:

class MyComponent {
  updateDirectiveInput() {
    this.directiveInputs.prop1 = 'new value';
  }
}

You can have multiple directives applied to same dynamic component (only one directive by same type):

import { dynamicDirectiveDef } from 'ng-dynamic-component';

@Component({
  selector: 'my-component',
  template: `
    <ng-container
      [ngComponentOutlet]="component"
      [ndcDynamicDirectives]="dirs"
    ></ng-container>
  `,
})
class MyComponent {
  component = MyDynamicComponent1;
  dirs = [
    dynamicDirectiveDef(MyDirective1),
    dynamicDirectiveDef(MyDirective2),
    dynamicDirectiveDef(MyDirective3),
    dynamicDirectiveDef(MyDirective1), // This will be ignored because MyDirective1 already applied above
  ];
}

NgComponentOutlet support

You can also use NgComponentOutlet
directive from @angular/common instead of <ndc-dynamic> and apply inputs and outputs to your dynamic components:

@Component({
  selector: 'my-component',
  template: `<ng-container [ngComponentOutlet]="component"
                           [ndcDynamicInputs]="inputs"
                           [ndcDynamicOutputs]="outputs"
                           ></ng-container>`
})
class MyComponent {
  component = MyDynamicComponent1;
  inputs = {...};
  outputs = {...};
}

Also you can use ngComponentOutlet with * syntax:

@Component({
  selector: 'my-component',
  template: `<ng-container *ngComponentOutlet="component;
                            ndcDynamicInputs: inputs;
                            ndcDynamicOutputs: outputs"
                            ></ng-container>`
})
class MyComponent {
  component = MyDynamicComponent1;
  inputs = {...};
  outputs = {...};
}

Extra

You can have more advanced stuff over your dynamically rendered components like setting custom injector ([ndcDynamicInjector])
or providing additional/overriding providers ([ndcDynamicProviders]) or both simultaneously
or projecting nodes ([ndcDynamicContent]).

NOTE: In practice functionality of this library is split in two pieces:

  • one - component (ndc-dynamic) that is responsible for instantiating and rendering of dynamic components;
  • two - directive (ndcDynamic also bound to ndc-dynamic) that is responsible for carrying inputs/outputs
    to/from dynamic component by the help of so called ComponentInjector (it is ndc-dynamic by default).

Thanks to this separation you are able to connect inputs/outputs and life-cycle hooks to different mechanisms of injecting
dynamic components by implementing ComponentInjector and providing it via DynamicModule.withComponents(null, [here]) in second argument.

It was done to be able to reuse NgComponentOutlet added in Angular 4-beta.3.

License

MIT © Alex Malkevich

主要指標

概覽
名稱與所有者gund/ng-dynamic-component
主編程語言TypeScript
編程語言JavaScript (語言數: 3)
平台
許可證MIT License
所有者活动
創建於2017-02-16 18:27:31
推送於2025-09-17 22:48:45
最后一次提交2025-09-17 22:48:36
發布數90
最新版本名稱v10.8.2 (發布於 )
第一版名稱v0.0.2 (發布於 2017-02-16 23:11:10)
用户参与
星數563
關注者數21
派生數65
提交數525
已啟用問題?
問題數168
打開的問題數0
拉請求數115
打開的拉請求數1
關閉的拉請求數236
项目设置
已啟用Wiki?
已存檔?
是復刻?
已鎖定?
是鏡像?
是私有?