How to dynamically add a directive?
Asked Answered
B

2

61

How to dynamically add (inject) a directive into host?

I have a myTooltip directive and I would like to add mdTooltip directive to it's host. I have tried setAttribute() of ElementRef.nativeElement, but it doesn't create the mdTooltip directive.

mytooltip.directive.ts:

@Directive({
  selector: '[my-tooltip]',
  host: {
    '(mouseenter)': 'show()',
    '(mouseleave)': 'hide()',
  }
})
export class myTooltip {
  @Input('my-tooltip') message;

  constructor() { }

  show() {
    /* TODO: How to add md-tooltip directive to elementref (host)? */
  }

  hide() {
    /* TODO: remove md-tooltip directive from elementref (host) */
  }
}

By host I mean the element that has myTooltip directive:

<span my-tooltip="tooltip hint">Click here</span>

The result wouldn't change above html but on mouseenter it would have md-tooltip directive in span.

BTW, the reason I am using a wrapper and not directly md-tooltip is that I want to later modify the showing delay, hiding delay and customize material tooltip's behaviour in other means as well.

Edit Apparently adding directives dynamically is not currently supported :( I think this question should still be here in case it material team updates that

Brooder answered 23/12, 2016 at 8:55 Comment(4)
Have you tried constructor(private tt:myTooltip) { console.log(tt); }? Not sure if this works. What is "host" actually? <span> doesn't look like a component.Imperturbable
You're talking about "injecting" when you request a provider in constructor, but in this case I don't mean that. What I mean by injecting here is to have a possibility to insert a directive into an already rendered dom element, a span, in this case. You would do this in html like this <span md-tooltip="tooltip hint">Click here</span>, but now I'm looking for a programmatic way of doing it.Brooder
That's not named or related to injecting. Adding directives dynamically is currently not supported, only components can be added dynamically.Imperturbable
Yes, sorry for misleading naming. I'll change the title to something more describing. I also read something about adding components dynamically, but that didn't apply for adding directives dynamically, thanks for the info.Brooder
D
54

That is a feature we are asking for in angular...read this: https://github.com/angular/angular/issues/8785

A quick and dirty way to do it is to use:

I have a directive named myHilite (to highlight text), I also have a component named MainComponent.ts. In MainComponent.ts I added this line of code...

export class MainComponent {
    @HostBinding('attr.myHilite') myHiliteDirective = new myHilite();
} 

If your directive requires parameters...

export class MainComponent {
    @HostBinding('attr.myHilite') myHiliteDirective = new myHilite(this.elementRef);
}

Your directive may need to execute code in one of its life cycle hooks, manually call the directive's lifecycle hook method in the parent component's lifecycle hook method like this...

export class MainComponent {
    //...code...

    ngOnInit(){
        this.myHiliteDirective.ngOnInit();
    }
}
Deloresdeloria answered 3/5, 2017 at 6:16 Comment(7)
@btinoco one more thing I want to clear is @HostBinding(attr.myDirective) is in child component and ngOnInit(){ this.myHilite.ngOnInit(); } is in parent's component. am I right?Pengelly
@btinoco can you please change myHilite to myHiliteDirective or myDirective so that other readers should not be confused about this.Pengelly
I edited the answer according to your comment, WasiF, but someone reverted it back to the original solution. Sorry.Proselytize
This worked for me nicely. However, is there a way to remove the directive afterwards? Basically, I want to be able to dynamically apply or remove the directive.Edrei
If I understand correctly, this wouldn't work with directives that have hostlisteners as those would not be attached to the nativeElement, right?Qatar
@FelipeCenteno sorry I have not try thatDeloresdeloria
@FelipeCenteno Seems like it wouldn't, but if lifecycle hooks are manual then initializing listeners on the directive can be done via a manual invoked method on the directve as well to initialize the listenersEgidio
A
4

Looks like this is coming in Angular 15.

See: https://www.angularjswiki.com/angular/directive-composition-api-in-angular-15/

Allnight answered 20/10, 2022 at 14:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.