0

Let's say I have this piece of code

<div *appTab routerLink="..." routerLinkActive="..."></div>

Is it possible to inject the RouterLinkActive Directive instance into my appTab Directive?

LppEdd
  • 20,274
  • 11
  • 84
  • 139
  • Yes, I think you can just add it to the constructor. – Reactgular Jun 05 '19 at 12:57
  • @Reactgular tried, unfortunately it doesn't work. `nullInjectorError: No provider for RouterLinkActive` – LppEdd Jun 05 '19 at 12:59
  • @Reactgular routerLinkActive is inside of appTab structural directive. – yurzui Jun 05 '19 at 13:03
  • @LiamFleming Then he will get completely different instance of RouterLinkActive directive – yurzui Jun 05 '19 at 13:04
  • I'm not sure what the class name is for the router link. I don't have my IDE open right now, but I thought it was named something like RouterLinkActiveDirective – Reactgular Jun 05 '19 at 13:05
  • @Reactgular `RouterLinkActive` is the correct name – LppEdd Jun 05 '19 at 13:13
  • Why are you prefixing the directive with `*`? Is this directive a structural template? – Reactgular Jun 05 '19 at 13:16
  • @Reactgular yep! The `div` will be picked up with `@ContentChildren` – LppEdd Jun 05 '19 at 13:21
  • I'm wondering if this is why you can't inject it. The `
    ` will be relocated to an inner template by the compiler. Try removing the `*` just to see if the injection works.
    – Reactgular Jun 05 '19 at 13:22
  • @Reactgular tried, doesn't work. What a pity. – LppEdd Jun 05 '19 at 13:29
  • Not sure if that has a chance to work: `
    `, where `appTabRouterLinkActive` would be an `@Input` property in `appTab`.
    – ConnorsFan Jun 05 '19 at 13:32
  • @ConnorsFan unfortunately structural directives doesn't seem to accept Inputs this way – LppEdd Jun 05 '19 at 13:40
  • You can try to implement the `@Input` property with the technique suggested in [this answer](https://stackoverflow.com/a/41791130/1009922). You may also have to make the correction suggested in [this other answer](https://stackoverflow.com/a/50036831/1009922). – ConnorsFan Jun 05 '19 at 13:53

1 Answers1

2

It would be easier if ViewContainerRefs.createEmbeddedView used correct injector but for now we can only workaround it.

router-link-active-tab-connector.directive.ts

import { Directive, Input, OnInit } from '@angular/core';
import { TabDirective } from './tab.directive';
import { RouterLinkActive } from '@angular/router';

@Directive({
  selector: '[routerLinkActive][routerLinkActiveTabConnector]'
})
export class RouterLinkActiveLinkerDirective implements OnInit {
  @Input('routerLinkActiveTabConnector') tab: TabDirective;

  constructor(private routerLinkActive: RouterLinkActive) {}

  ngOnInit() {
    this.tab.setRouterLinkActive(this.routerLinkActive);
  }
}

tab.directive.ts

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

@Directive({
  selector: '[appTab]'
})
export class TabDirective {

  constructor(private vcRef: ViewContainerRef, private templateRef: TemplateRef<any>) { }

  setRouterLinkActive(routerLinkActive: RouterLinkActive) {
    console.log(routerLinkActive);
    // do something with RouterLinkActive directive
  }

  ngOnInit() { 
    this.vcRef.createEmbeddedView(this.templateRef, { $implicit: this});
  }
}

html

<div *appTab="let tabRef" 
  routerLink="..." 
  routerLinkActive="" 
  [routerLinkActiveTabConnector]="tabRef">
   Some content
</div> 

Ng-run Example

yurzui
  • 205,937
  • 32
  • 433
  • 399