'Can we select <a> element when it's routerLink is active in angular?
I want to select <a> element by className when its router link is active, but it returns null
navbar.component.html code:
<nav class="profile-navbar">
<ul>
<li class="posts-item">
<a
[routerLink]="['/app/profile', username, 'posts']"
routerLinkActive="active-link"
>Posts</a
>
</li>
<li class="images-item">
<a
[routerLink]="['/app/profile', username, 'images']"
routerLinkActive="active-link"
>Images</a
>
</li>
</ul>
</nav>
navbar.component.ts code:
import { AfterViewInit, Component, OnInit } from '@angular/core';
@Component({
selector: 'profile-navbar',
templateUrl: './navbar.component.html',
styleUrls: ['./navbar.component.scss']
})
export class NavbarComponent implements OnInit, AfterViewInit {
constructor() {
}
ngOnInit(): void {
}
ngAfterViewInit(): void {
const activeLink = document.querySelector('.active-link');
console.log(activeLink)
}
}
How can I select the element the element based on routerLinkActive class??
Solution 1:[1]
To get a series of "divs" you can use a template reference variable and ViewChildren. When you has ViewChildren you can find the element with a class or anopther property.
Case of routerLinks the approach is similar, but you can to have in ViewChildren the [routerLinksActive seeing as "ElementRef" and seeing as "RouterLinkActive"
Some like
//links are the "RouterLinkActive"
@ViewChildren(RouterLinkActive) links:QueryList<RouterLinkActive>
//lisk are the "RouterLinkAvtive" but seeing as ElementRef
@ViewChildren(RouterLinkActive,{read:ElementRef}) linksElements:QueryList<ElementRef>
@ViewChild('indicator') indicator:ElementRef
constructor(private router: Router) {}
ngOnInit() {
this.router.events.pipe(
filter(x=>x instanceof NavigationEnd),
startWith(null)).subscribe(res=>{
//we need enclosed in a setTimeout because when the event NavigationEnd
//happens, Angular are not add the class "active-links"
// nor link isActive=true
setTimeout(()=>{
//first find the "index" in the QueryList
const index=(this.links.map(
(x:RouterLinkActive,i:number)=>({isActive:x.isActive,index:i}))
.find(x=>x.isActive) || {index:-1}).index
//it's the same index in the ElementRef
if (index>=0)
{
const el=this.linksElements.find((_,i)=>i==index)
//We use the "el" to change the style.top of the indicator
this.indicator.nativeElement.style.top=
el.nativeElement.offsetTop+'px'
}
else
{
this.indicator.nativeElement.style.top='-100px'
}
})
})
}
Where
<nav class="profile-navbar">
<ul>
<li class="posts-item">
<a
[routerLink]="['/hello']"
routerLinkActive="active-link"
>Posts</a
>
</li>
<li class="images-item">
<a
[routerLink]="['/by']"
routerLinkActive="active-link"
>Images</a
>
</li>
</ul>
<div #indicator class="indicator"></div>
</nav>
like is showed in this stackblitz
Solution 2:[2]
You can't use this LifeCycleHook try ngDoCheck() instead or listen to the route changes (How to detect a route change in Angular?) and do your selection based on the event or even better just use in your .css file:
a.active {
/* your style */
}
If you just want to style it, there is usually no need to select it, but in your case with the calculation of translate3d and scaleX I'm not sure...
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Eliseo |
| Solution 2 |
