Adding a component to TemplateRef using a structural directive

We are creating an angular 4 component library, and one of the components is a busy component. The purpose of the component is to give the developer the ability to create an overlay on any given HTML element that contains spinner graphics.

<div *xuiBusy="isBusy">...</div>

When the value is isBusytrue, we want to add to the inner content divso that we can present overlay elements on top of the content.

We were able to add the component to ViewContainerRef, however this adds an element of employment as a related to div, rather than to, divat will.

    ngOnInit(): void {
      const compFactory = this._componentFactory.resolveComponentFactory(XuiBusyComponent);
      const comp = this._viewContainer.createComponent(compFactory);

What the consumer does:

<div *xuiBusy="isBusy">
  <span>This is the content</span>
</div>

isBusy true, , . , <spinner> div.

<div *xuiBusy="isBusy">
  <span>This is the content</span>
  <spinner>Please wait...</spinner> <-- inserted by directive
</div>

!

+4
1

Demo

StackBlitz. Spinner, Busy- app.component.ts .

:

Angular .

constructor(private templateRef: TemplateRef<void>,
            private vcr: ViewContainerRef,
            private cfr: ComponentFactoryResolver) { }

. (, , ), , .

, bindingPropertyName Input.

@Input('xuiBusy') isBusy: boolean;

, , createEmbeddedView, ViewContainerRef. , , : TemplateRef, .

this.vcr.createEmbeddedView(this.templateRef)

, factory, , .

resolveComponentFactory ComponentFactoryResolver.

const cmpFactory = this.cfr.resolveComponentFactory(SpinnerComponent)

factory createComponent , .

this.vcr.createComponent(cmpFactory)

, , isBusy true, .

if (this.isBusy) {
  const cmpFactory = this.cfr.resolveComponentFactory(SpinnerComponent)
  this.vcr.createComponent(cmpFactory)
}

Angular , . , Angular , . Spinner, .

Angular , NgModule.entryComponents.

@NgModule({
  ...
  entryComponents: [SpinnerComponent],
  ...
})

@Directive({selector: '[xuiBusy]'})
export class BusyDirective implements OnInit {

  @Input('xuiBusy') isBusy: boolean;

  constructor(private templateRef: TemplateRef<void>,
              private vcr: ViewContainerRef,
              private cfr: ComponentFactoryResolver) { }

  ngOnInit() {
    this.vcr.createEmbeddedView(this.templateRef)
    if (this.isBusy) {
      const cmpFactory = this.cfr.resolveComponentFactory(SpinnerComponent)
      this.vcr.createComponent(cmpFactory)
    }
  }

}

( )

<div *xuiBusy="true">
  <span>This is some content</span>
</div>

<div *xuiBusy="false">
  <span>This is some content</span>
</div>
+3

Source: https://habr.com/ru/post/1677026/


All Articles