Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Angular structural directive: wrap the host element with some another component

I have simplest Angular structural directive:

import { Directive, TemplateRef, ViewContainerRef } from '@angular/core';

@Directive({ selector: '[hello]' })
export class HelloDirective {
  constructor(
    private templateRef: TemplateRef<any>, private viewContainer: ViewContainerRef) {
      this.viewContainer.createEmbeddedView(this.templateRef);
  }
}

I use it this way:

<div *hello>Hello Directive</div>

It shows me "Hello Directive" message as expected. Now I want to change the content by wrapping it with some another component:

<my-component>Hello Directive</my-component>

And I want the directive to do it for me. I know that I can use a Component paradigm and create HelloComponent instead of HelloDirective and use ng-template etc with the template defined by template or templateUrl property on the @Component decorator... But is there an approach that could be used with a Directive paradigm to achieve such a result?

like image 844
dhilt Avatar asked Nov 18 '17 03:11

dhilt


People also ask

What is the difference between @component and @directive in Angular?

Component is used to break up the application into smaller components. But Directive is used to design re-usable components, which is more behavior-oriented. That is why components are widely used in later versions of Angular to make things easy and build a total component-based model.

Can we use two structural directive in a single HTML element?

Comparing Component and Structural Directives A component directive can be created multiple times, that is, every component in Angular will have a @Component decorator attached, while we cannot apply more than one structural directive to the same HTML element.

What is Templateref?

TemplateReflinkRepresents an embedded template that can be used to instantiate embedded views. To instantiate embedded views based on a template, use the ViewContainerRef method createEmbeddedView() .

What is * in structural directive?

Structural directives are responsible for the Structure and Layout of the DOM Element. It is used to hide or display the things on the DOM. Structural Directives can be easily identified using the '*'. Every Structural Directive is preceded by a '*' symbol.


1 Answers

You can create component dynamically and pass projectable nodes to it. So it could look like

@Directive({ selector: '[hello]' })
export class HelloDirective implements OnInit, DoCheck {
  templateView: EmbeddedViewRef<any>;
  constructor(
      private templateRef: TemplateRef<any>,
      private viewContainer: ViewContainerRef,
      private resolver: ComponentFactoryResolver) {
  }

  ngOnInit() {
    this.templateView = this.templateRef.createEmbeddedView({});
    const compFactory = this.resolver.resolveComponentFactory(MyComponent);
    this.viewContainer.createComponent(
      compFactory, null, this.viewContainer.injector, [this.templateView.rootNodes])
  }

  ngDoCheck(): void {
    if (this.templateView) {
        this.templateView.detectChanges();
    }
  }
}

You have to add MyComponent to entryComponents array of your @NgModule

Complete example can be found on Stackblitz

See also

  • Creating a angular2 component with ng-content dynamically
like image 187
yurzui Avatar answered Oct 18 '22 06:10

yurzui