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?
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.
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.
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() .
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With