14

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?

4
  • Do you want to transclude directive's contents into component? Commented Nov 18, 2017 at 4:02
  • @yurzui Yes, and then pass the result into the initial template instead of directive's content. So that it could be interpreted as <div *hello><my-component>Hello Directive</my-component></div> at the end (instead of <div *hello>Hello Directive</div>). Commented Nov 18, 2017 at 4:13
  • Does my-component contain ng-content? Commented Nov 18, 2017 at 4:16
  • @yurzui It could be fully customized to provide proper behavior. No limitations on my-component implementation in this task. Commented Nov 18, 2017 at 4:28

1 Answer 1

18

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

Sign up to request clarification or add additional context in comments.

4 Comments

If I use an nested component inside hello directive, it doesn't work. Do you have a sugesstion to fix that: stackblitz.com/edit/angular-97ckey?embed=1&file=app/…
@MuratÇorlu Did you mean hello component didn't get input? That's because its view is not part of angular change detection tree. Try this stackblitz.com/edit/angular-jrtnmn?file=app/app.component.ts
Great, thanks. Another question is, now hello component in hello directive is initializing when directive is embedded the content, but not destroying when content is removed: stackblitz.com/edit/… do you also have a suggestion to destroy hello component when we remove content from dom?
@yurzui I have had a dx-text-box from devextreme, and code was not working, after I fixed the issue I updated your answer (since many developers copy paste and they want it to work out of the box)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.