Upgrade to Pro — share decks privately, control downloads, hide ads and more …

It’s Alive! Dynamic Components in Angular

It’s Alive! Dynamic Components in Angular

The main use-case for using dynamic components is when we can decide only in run-time which component is loaded. They’re also the only solution when we want to embed Angular components in non-Angular ones. In many cases, replacing in-template components with dynamic ones is beneficial to performance and code quality. In this talk we’ll learn how to create and use dynamic components, and discuss several types of usages.

Shmuela Jacobs

August 11, 2018
Tweet

More Decks by Shmuela Jacobs

Other Decks in Programming

Transcript

  1. STATIC COMPONENTS ➤ Used in template ➤ Known in development

    time ➤ Fixed location ➤ Hard-coded <app-header></app-header> <div id="main"> <tabset> <tab title="Notes"> <app-note *ngFor="let note of notes" [text]="note.text" [date]="note.date" (update)="saveNote($event)"> </app-note> </tab> <tab> <app-dashboard></app-dashboard> </tab> </tabset>
  2. STATIC COMPONENTS <div *ngFor="let component of components"> <div ngSwitch="component.type"> <app-note

    *ngSwitchCase="note" [data]="component.data" (write)="update(component, $event)"> </app-note> <app-graph *ngSwitchCase="graph" [data]="component.data" (select)="update(component, $event)"> </app-graph> <app-bar-graph *ngSwitchCase="barGraph" [data]="component.data" (change)="update(component, $event)"> </app-bar-graph> <app-gauge *ngSwitchCase="gauge" [data]="component.data" (move)="update(component, $event)"> </app-gauge> <app-table *ngSwitchCase="table" [data]="component.data" (selectRow)="update(component, $event)"> </app-table> </div> </div>
  3. DYNAMIC COMPONENTS ➤ Added in run time ➤ Load the

    configuration from the server ➤ Lazy loaded <div #vc></div> @ViewChild('vc', { read: ViewContainerRef }) vc; constructor(private cfr: ComponentFactoryResolver){} this.components.forEach(component => { this.vc.create(this.cfr.resolveComponentFactory(component)) });
  4. DYNAMIC COMPONENTS ➤ Dashboards ➤ Data-driven forms ➤ Popups &

    Modals ➤ Content Management Systems ➤ Example: Angular.io
  5. DYNAMIC COMPONENTS ➤ Dashboards ➤ Data-driven forms ➤ Popups &

    Modals ➤ Content Management Systems ➤ Example: Angular.io ➤ Embedded into foreign components ➤ Example: JointJS (Backbone) Juri Strumpflohner
 Use Dynamic Components to render HTML for 3rd party libraries
 https://juristr.com/blog/2017/11/dynamic-angular-components-for-rendering-html
  6. DYNAMIC COMPONENTS ➤ Dashboards ➤ Data-driven forms ➤ Popups &

    Modals ➤ Content Management Systems ➤ Example: Angular.io ➤ Embedded into foreign components ➤ Example: JointJS (Backbone) ➤ Plugins ➤ Example: Wizer.Me Maxim NgWizard Koretskyi Modules are not what you think they are
  7. COMPONENT INSTANTIATION NgModule Declarations compile SomeComponent SomeComponent Factory create SomeComponent

    View DOM Node Component Instance render <app-note *ngSwitchCase="note" [data]="component.data" (write)="update($event)"> </app-note>
  8. COMPONENT INSTANTIATION NgModule Declarations Entry Components compile SomeComponent SomeComponent Factory

    create SomeComponent View DOM Node Component Instance render <app-root></app-root> this.vc.create( this.cfr.resolveComponentFactory(component)) }); SomeComponent Host Factory
  9. DYNAMIC COMPONENTS ➤ Where is the component inserted? ➤ How

    is it instantiated? @Component({ template: `<div #vc></div>` }) export class HomeComponent { @ViewChild('vc', { read: ViewContainerRef }) vc; constructor( private injector: Injector, private cfr: ComponentFactoryResolver) {} addDynamicComponent() { const cmpFactory = this.cfr.resolveComponentFactory(NoteComponent); const componentRef = cmpFactory.create(this.injector); this.vc.insert(componentRef.hostView); }
  10. DYNAMIC COMPONENTS ➤ Where is the component inserted? ➤ How

    is it instantiated? constructor( private cfr: ComponentFactoryResolver) {} addDynamicComponent() { const cmpFactory = this.cfr.resolveComponentFactory(NoteComponent); // const componentRef = cmpFactory.create(this.injector); // this.vc.insert(componentRef.hostView); this.vc.createComponent(cmpFactory); } @Component({ template: `<div #vc></div>` }) export class HomeComponent { @ViewChild('vc', { read: ViewContainerRef }) vc;
  11. DYNAMIC COMPONENTS ➤ How to pass inputs? ➤ How to

    bind to outputs? ➤ Notice: Change detection works, 
 but ngOnChanges will not be called (ngDoCheck will) componentRef.instance.data = this.getData(); componentRef.instance.event.subscribe(console.log)
  12. DYNAMIC COMPONENTS ➤ It's still not 100% dynamic... const cmpFactory

    = this.cfr.resolveComponentFactory(NoteComponent);
  13. PLUGIN COMPONENTS ➤ Unknown in compile time ➤ Lazy loaded

    modules constructor( private injector: Injector, private loader: NgModuleFactoryLoader) {} addPlugin() { this.loader.load('path/to/plugin/plugin.module#PluginModule') .then((factory) => { const module = factory.create(this.injector); const cfr = module.componentFactoryResolver; const cmpFactory = cfr.resolveComponentFactory(PluginComponent); this.vc.createComponent(cmpFactory); }); }
  14. PLUGIN COMPONENTS ➤ Build a module separately with Angular CLI

    - angular.json "projects": { "ng-talks-demo": { ... "architect": { "build": { ... "options": { "lazyModules": [ "path/to/plugin/plugin.module" ], ...
  15. PLUGIN COMPONENTS ➤ Unknown in compile time ➤ Lazy loaded

    modules constructor( private injector: Injector, private loader: NgModuleFactoryLoader) {} addPlugin() { this.loader.load('path/to/plugin/plugin.module#PluginModule') .then((factory) => { const module = factory.create(this.injector); const cfr = module.componentFactoryResolver; const cmpFactory = cfr.resolveComponentFactory(PluginComponent); this.vc.createComponent(cmpFactory); }); }
  16. PLUGIN COMPONENTS ➤ Use providers! @NgModule({ declarations: [PluginComponent], entryComponents: [PluginComponent],

    providers: [ { provide: 'widgets', useValue: [ { name: 'plugin-cmp', component: PluginComponent } ], multi: true } ] }) export class PluginModule {}
  17. PLUGIN COMPONENTS ➤ Unknown in compile time ➤ Lazy loaded

    modules constructor( private injector: Injector, private loader: NgModuleFactoryLoader) {} addPlugin() { this.loader.load('path/to/plugin/plugin.module#PluginModule') .then((factory) => { const module = factory.create(this.injector); const cfr = module.componentFactoryResolver; const widgets = module.injector.get('widgets'); const cmpFactory = cfr.resolveComponentFactory(widgets[0][0].component); this.vc.createComponent(cmpFactory); }); }
  18. DYNAMIC COMPONENTS - MY RESOURCES ➤ Juri Strumpflohner
 Use Dynamic

    Components to render HTML for 3rd party libraries
 https://juristr.com/blog/2017/11/dynamic-angular-components-for-rendering-html ➤ Maxim NgWizard Koretskyi ➤ Modules are not what you think they are - UP NEXT! ➤ Here is what you need to know about dynamic components in Angular
 https://blog.angularindepth.com
 ➤ Manfred Steyer 
 Angular Elements Dashboard
 https://github.com/manfredsteyer/angular-elements-dashboard