Home > Software design >  Angular 12 D3 tree displaying a routerLink
Angular 12 D3 tree displaying a routerLink

Time:03-08

I would like to display a routerLink inside my d3.tree(), but I am struggling with getting it displayed as a hyperlink.

I have tried like this

.append("a")
.html(`<a [routerLink]="['/mycomponent']" fragment="1.1">link to user component</a>`);

given that this

.append("a")
.html(`<a href="mycomponent#1.1">link to user component</a>`);

works, but I don't want the whole page to reload.

The code with routerLink just writes the text and it is not clickeable, while everything is displayed correctly when just writing it into the component itself.

CodePudding user response:

create custom-link.directive.ts

@Directive({
  selector: "[linkify]",
})

// * Apply Angular Routing behavior, PreventDefault behavior
export class CustomLinkDirective {
  @Input()
  appStyle: boolean = true;
  constructor(
    private router: Router,
    private ref: ElementRef,
    @Inject(PLATFORM_ID) private platformId: Object
  ) {}

  @HostListener("click", ["$event"])
  onClick(e: any) {
    e.preventDefault();
    const href = e.target.getAttribute("href");
    href && this.router.navigate([href]);
  }

  // * styling
  ngAfterViewInit() {
    if (isPlatformBrowser(this.platformId)) {
      this.ref.nativeElement.querySelectorAll("a").forEach((a: HTMLElement) => {
        const href = a.getAttribute("href");
        href &&
          this.appStyle &&
          a.classList.add("text-indigo-600", "hover:text-indigo-500");
      });
    }
  }
}

use it

const apiSectionText= "Take <a href='/tracking-api'>Tracking API</a> and <a href='/tracking-webhook'>Tracking Webhook</a> solutions,"


 <p linkify
    
    [innerHtml]="apiSectionText"
    ></p> 

CodePudding user response:

Angular not compile, so if you add an .html you can not use "Angular" to control. You need make in JavaScript.

The problem when mixing JavaScript and Angular is that we can not trust in the name of the functions. So we need dispatch a CustomEvent and subscribe to it

Well, we are going to create a function that gets all the "link" inside a div I call wrapper and use a template reference variable

<div #wrapper>
  <div [innerHTML]="link"></div>
</div>

  createLinks()
  {
    //get the "links" inside the "wrapper"
    const links = this.wrapper.nativeElement.getElementsByTagName('a');
      
      //with each link
      for (var i = 0; i < links.length; i  ) {
          //we change the color only to check if work
          links[i].style.color = 'red';

          //we override the event click
          links[i].onclick = (event) => {
            //prevent default
            event.preventDefault();

            //get the "target" using getAttribute('href')
            const target = (event.target as HTMLElement).getAttribute('href');

            //dispatch a custom event in "wrapper"

            this.wrapper.nativeElement.dispatchEvent(
              new CustomEvent<string>('route', { detail: target })
            );
          };
      }
  }

//and in ngOnInit, we subscribe to the custom event

ngOnInit()
{
  fromEvent(this.wrapper.nativeElement, 'route').subscribe((res: any) => {
        this.router.navigate([res.detail]);
      });
  }
}

A simple stackblitz

NOTE: See in the stackblitz that I call to the function "createLink" "after" all is painted. In the stackblitz I use a setTimeout to give time to Angular to paint -in this case I coud use ngAfterViewInit, but in case you create the D3 tree you need call it after paint the 3D

  • Related