04 mar 2026
8 min

RouterLink, RouterLinkActive czyli podstawy nawigowania w Angularze

W tym artykule chciałbym skupić się i zgłębić temat nawigowania w Angularze. Jak wiemy, nawigacja w rozwiązaniach typu Single Page Applications (SPAs) różni się nieco od klasycznego podejścia. 

Standardowo podczas nawigacji aplikacje wysyłały request do serwera, by ten zwrócił im odpowiedni szablon HTML. Działo się tak co każdą zmianę URLa w aplikacji.

SPA wyróżnia to, że przeglądarka dostaje od serwera tylko jedną stronę w postaci index.html. Jak więc rozwiązać problem nawigowania w takiej aplikacji? 

Na szczęście nie musimy nad tym wiele główkować, ponieważ Angular ma dla nas gotowe rozwiązanie. Gdy użytkownik naszej aplikacji zmienia ścieżkę, client-side router przejmuje stery i aktualizuje to, co widzimy, bez przeładowywania całości strony.

Podejście deklaratywne- template’y html

Dyrektywa RouterLink jest deklaratywnym podejściem do nawigacji, które pozwala bez przeszkód używać standardowego anchor taga <a> w Angularze.

Jak używać routerLink?

Użycie naszej deklaratywnej metody jest proste, zastępujemy klasyczny atrybut href dyrektywą routerLink z odpowiednią ścieżką.

<!-- Standardowe podejście -->
<a href="https://angular.love/roadmap">Roadmap</a>

By wykorzystać tą metodę musimy jednak pamiętać o imporcie RouterLinka z biblioteki @angular/router

<!-- Deklaratywne podejście -->
import {RouterLink} from '@angular/router';

<a routerLink="roadmap">Roadmap</a>

W tym miejscu należy zaznaczyć, że routerLink nie służy do nawigacji zewnętrznej i działa tylko w obrębie routingu naszej Angularowej aplikacji.

Udogodnienia dyrektywy deklaratywnej

Dyrektywa ta ma wiele udogodnień. Jednym z najbardziej podstawowych jest oczywiście możliwość wykorzystania relatywnych URL’i. Pozwala to uniknąć sztywnych, statycznych linków, które powodują przeładowywanie strony i utratę state’u naszej aplikacji. Dzięki wykorzystaniu tego rozwiązania, nasza aplikacja jest elastyczna a my unikamy błędów przy dokonywaniu zmian środowiskowych. Kod będzie działał poprawnie niezależnie od tego jaki jest baseUrl aplikacji. 

<!-- absolute url -->
<a href="https://www.angular.love/roadmap">Roadmap</a>
<!-- relative url -->
<a href="/roadmap">Roadmap</a>

W Angularze możemy zapisywać takie relatywne URL’e na dwa sposoby. Zarówno pierwszy jak i drugi jest poprawny.

<a routerLink="roadmap">Roadmap</a>
<a [routerLink]="['roadmap']">Roadmap</a>

Array jako parametr

Drugi sposób, w którym wykorzystujemy tablicę (array), pozwala nam na dynamiczne budowanie kolejnych części naszego URL’a. Segmenty możemy podawać po przecinku i mogą być one zarówno string’ami jak i number’ami. Najłatwiej sposobem na zrozumienie tego będzie spojrzenie na przykład poniżej.

<!--  przy założeniu, że id to string "router-link" po kliknięciu link mógłby wyglądał tak https://angular.love/roadmap/router-link -->
<a [routerLink]="['roadmap', id]">Roadmap</a>

Dodatkowo dostajemy możliwość wyboru czy nasza ścieżka ma być relatywna do naszego obecnego URL’a, w którym się znajdujemy, czy do root domain. Ponownie najlepiej zobaczyć przykład kodu, by w pełni to zrozumieć.

<!-- Zakładamy, że użytkownik znajduje się pod ścieżką /settings i chce przejść na /settings/notifications -->


<!-- Link relatywny -->
<a routerLink="notifications"> Notifications </a>


<!-- Link absolutny – działa niezależnie od aktualnej lokalizacji -->
<a routerLink="/settings/notifications"> Notifications </a>


<!-- Przykład routerLink wykorzystującego string -->
<a [routerLink]="'/settings' + '/notifications'">Notifications</a>


<!-- Przykład routerLink z wykorzystaniem tablicy -->
<a [routerLink]="['/settings', 'notifications']"> Notifications </a>


<!-- Statyczna ścieżka -->
<a routerLink="/team/123/user/456"> User 456</a>


<!-- Dynamiczne segmenty trasy -->
<a [routerLink]="['/team', teamId, 'user', userId]"> Current User </a>

Dodatkowe parametry – query params i fragmenty

Nasze linki mogą także nieść w sobie dodatkowe informacje w postaci parametrów zapytań (query params) oraz fragmentów. Query params zazwyczaj są przez nas wykorzystywane by zarządzać stanem strony lecz nie zmieniać jej struktury. Fragment czasem nazywany kotwicą jest wykorzystywany do precyzyjnej nawigacji do konkretnego elementu na stronie (po ID), zamiast tylko do samej ścieżki routingu. Spójrz na przykłady poniżej, które ułatwią poznanie tych dwóch zagadnień.


<!-- Po przejściu URL będzie wyglądał tak: /notifications?debug=true&message=new -->
<a routerLink="notifications" [queryParams]="{ debug: true, message: 'new' }">Notifications</a>


<!-- Po przejściu URL będzie wyglądał tak: /notifications#desktop -->
<a routerLink="notifications" fragment="desktop">Notifications</a>

Dodawanie klas do aktywnych linków – RouterLinkActive

W naszych aplikacjach bardzo często potrzebujemy wykrywać i dynamicznie ostylowywać linki odpowiadające ścieżce, w której aktualnie znajduje się użytkownik. Angular daje nam do tego gotową dyrektywę w postaci RouterLinkActive, którą oczywiście musimy zaimportować z biblioteki @angular/router. 

Oprócz dodawania odpowiedniej klasy do aktywnego linku możemy zadbać w łatwy sposób o dostępność, dodając ariaCurrentWhenActive. Atrybut ten informuje użytkowników screen readerów i innych podobnych urządzeń o obecnej pozycji w nawigacji poprzez dodanie aria-current. Poniżej prosty przykład prosto z oficjalnej dokumentacji

<nav>
 <a
   class="button"
   routerLink="/about"
   routerLinkActive="active-button"
   ariaCurrentWhenActive="page"
 >
   About
 </a>
 |
 <a
   class="button"
   routerLink="/settings"
   routerLinkActive="active-button"
   ariaCurrentWhenActive="page"
 >
   Settings
 </a>
</nav>


/* Aktywny link będzie miał tekst koloru czerwonego */
.active-button{
   color: red;
}

Nie musimy jednak ograniczać się wyłącznie do jednej klasy, możemy dodać ich wiele do naszego linku poprzez zastosowanie tablicy.

<a routerLink="/user/bob" [routerLinkActive]="['class1', 'class2']">Bob</a>

Należy jednak pamiętać o tym, że RouterLinkActive będzie “aktywny” również wtedy, gdy adres URL jest dzieckiem lub dalszym członkiem linku. Chcąc pozbyć się tego zachowania, możemy dodać dyrektywę routerLinkActiveOptions z obiektem konfiguracyjnym zawierającym informację o konieczności dokładnego dopasowania. Domyślnie Angular dopasowuje ścieżki bez tej opcji, link /user byłby aktywny dla każdej podstrony zaczynającej się od /user.

<!-- Przy założeniu, że użytkownik znajduje się pod ścieżką:
/user/jane/role/admin -->


<!-- Będzie aktywny -->
<a [routerLink]="['/user/jane']" routerLinkActive="active-link"> User </a>


<!-- Będzie aktywny -->
<a [routerLink]="['/user/jane/role/admin']" routerLinkActive="active-link"> Role </a>


<!-- Nie będzie aktywny -->
<a
 [routerLink]="['/user']"
 routerLinkActive="active-link"
 [routerLinkActiveOptions]="{ exact: true }"
>
 User
</a>

Dyrektywa może być także przypisana do elementu nadrzędnego, co pozwoli na swobodne nadawanie stylów w wybranym przez nas miejscu. Znów posłużę się przykładem z Angular.dev

<div routerLinkActive="active-link" [routerLinkActiveOptions]="{exact: true}">
 <a routerLink="/user/jim">Jim</a>
 <a routerLink="/user/bob">Bob</a>
</div>

Nawigacja funkcyjna

Wcześniejsze deklaratywne podejście pozwala nam na obsługę nawigacji w szablonach HTML. Co jednak, gdy potrzebujemy nawigować użytkownika naszej aplikacji w zależności od jakiejś logiki bądź stanu w kodzie itp.?  Pozwala nam na to Router, który oferuje szeroką gamę funkcji do kontrolowania tego zachowania w typescriptowym kodzie.

import {Router} from '@angular/router';
@Component({

})
export class AppDashboard {
private router = inject(Router);

}

Wstrzyknięcie Routera umożliwia nam przede wszystkim na proste nawigowanie, korzystając z metody navigate:

navigateToSettings(): void{
this.router.navigate([‘/settings’]);
}

Możemy oczywiście też podać do naszego routera parametry jak route, query lub matrix:

 navigateToCategory(category: string): void {
   // route parameters
   this.router.navigate(['/category', category]);
   // query parameters
   this.router.navigate(['/category'], {
     queryParams: { category: category, sort: 'quantity' },
   });
   // matrix parameters
   this.router.navigate(['/category', { category: category, sort: 'quantity' }]);
 }

RelativeTo

Możemy zauważyć, że router.navigate() pomaga nam w prostych i złożonych zagadnieniach, jednak to nie wszystko. Metoda ta umożliwia budowanie dynamicznych nawigacyjnych ścieżek relatywnych do lokalizacji naszego komponentu poprzez użycie klauzuli relativeTo. Znów pozwolę sobie wykorzystać przykład z oficjalnej dokumentacji, który w przejrzysty sposób pokazuje wykorzystanie wyżej wspomnianej klauzuli:

import { Router, ActivatedRoute } from '@angular/router';
@Component({
 selector: 'app-user-detail',
 template: `
   <button (click)="navigateToEdit()">Edit User</button>
   <button (click)="navigateToParent()">Back to List</button>
 `,
})
export class UserDetail {
 private route = inject(ActivatedRoute);
 private router = inject(Router);
 // do rodzeństwa
 navigateToEdit() {
   // z: /users/123
   // do:   /users/123/edit
   this.router.navigate(['edit'], { relativeTo: this.route });
 }
 // do rodzica
 navigateToParent() {
   // z: /users/123
   // do:   /users
   this.router.navigate(['..'], { relativeTo: this.route });
 }
}

Przechodzenie do pełnej ścieżki

Zinjectowanie Routera pozwala nam również na wykorzystanie metody navigateByUrl(). Metoda ta umożliwia przejście do wskazanego adresu na podstawie pełnej ścieżki URL bez przekazywania jej jako tablicy. Przydaje się to w sytuacjach, w których dysponujemy kompletnym adresem URL na przykład przy deep linkach lub gdy ścieżka nawigacji pochodzi z zewnętrznego źródła.

router.navigateByUrl('/search?category=books&sortBy=price');

Kontrolowanie zachowania routera

Angular daje nam możliwość kontrolowania zachowania routera podczas przechodzenia między ścieżkami. Służy do tego interfejs NavigationBehaviorOptions, który jest gotowym zestawem narzędzi do wykorzystania w metodach router.navigate() lub router.navigateByUrl(). 

Pierwszą opcją do wykorzystania jest onSameUrlNavigation. Służy ona do konfiguracji zachowania, w którym użytkownik próbuje przejść na ten sam URL, na którym obecnie się znajduje. Domyślnie Angular nie robi wtedy nic , jednak z opcją ‘reload’ wymusi przejście przez cały proces nawigacji ponownie (np. Guardy, Resolvery). Opcja reload nie odświeża całego komponentu!

this.router.navigate(['stocks'], { onSameUrlNavigation: 'ignore' }); //domyślna opcja, nie zrobi nic jeżeli jesteśmy w tym samym URL’u
this.router.navigate(['stocks'], { onSameUrlNavigation: 'reload' }); //opcja, która pozwoli na przejście przez cały proces nawigacji ponownie

Drugą z nich jest skipLocationChange, która przyjmuje boolean jako argument. Gdy ustawimy tę opcję jako true, nawigacja przekieruje nas do nowej ścieżki, ale nie zapisze jej w historii przeglądarki. Nie zobaczymy też tego url’a na pasku w przeglądarce. Przykładem wykorzystania tej opcji może być sytuacja, w której np. po kliknięciu wstecz nie chcemy, żeby user wrócił do danej ścieżki.

this.router.navigate(['/stocks'], { skipLocationChange: true });

Metodą przeciwną – pozwalającą na nadpisanie obecnej ścieżki w historii jak i na pasku przeglądarki jest replaceUrl. Tak samo jak poprzednia, przyjmuje boolean jako argument. Prostym przykładem zastosowania opcji replaceUrl może być uniknięcie próby powrotu usera do strony logowania po zalogowaniu się.

this.router.navigate(['/stocks'], { replaceUrl: true });

Dynamiczne klasy dzięki isActive

Wiedzą, którą warto przyswoić w kontekście routera jest funkcja isActive. Funkcja ta zwraca booleana owiniętego w computed signal. Ten z kolei informuje nas o tym, czy obecny URL jest aktywny. Przykładowym wykorzystaniem takiego sygnału może być dodanie klasy w template HTML, tak jak miało to miejsce w RouterLinkActive. Dla rozjaśnienia załączam jak zwykle przydatny przykład z dokumentacji.

import {Component, inject} from '@angular/core';
import {isActive, Router} from '@angular/router';
@Component({
 template: `
   <div [class.active]="isSettingsActive()">
     <h2>Settings</h2>
   </div>
 `,
})
export class Panel {
 private router = inject(Router);
 isSettingsActive = isActive('/settings', this.router, {
   paths: 'subset',
   queryParams: 'ignored',
   fragment: 'ignored',
   matrixParams: 'ignored',
 });
}

UrlTree

Chcąc wyczerpać podstawowe tematy nawigowania, nie możemy zapomnieć o UrlTree. Jest to jedna z rzeczy, które dzieją się pod maską Angulara. Moglibyśmy pomyśleć, że URL jest traktowany jako płaski ciąg znaków, jednak jest to błędne myślenie. Adres jest rozbijany na strukturę drzewa, z której możemy wyróżnić segmenty, parametry i dzieci.

// /stocks?showDetails=true#section-top
const urlTree: UrlTree = this.router.parseUrl(this.router.url);
console.log(this.router.url);
console.log(urlTree);

Powyższy, krótki snippet kodu pomaga nam pokazać, jak faktycznie wygląda takie drzewo. Wyniki logów z konsoli możecie zobaczyć poniżej.

UrlTree in Angular
Możemy również sami generować takie drzewa z własnymi właściwościami dzięki createUrlTree. Gdybyśmy sami tworzyli takiego stringa z adresem istnieje ryzyko, że zrobimy coś źle. Metoda createUrlTree przyjmuje array’a a Angular sam dba o “zbicie” takiego URL’a.
// create /team/33/user/11
router.createUrlTree(['/team', 33, 'user', 11]);
// create /team/33;expand=true/user/11
router.createUrlTree(['/team', 33, {expand: true}, 'user', 11]);

RouterLink oprócz przyjmowania tablicy segmentów, może także przyjąć nasz UrlTree. Funkcjonalność ta jest niezwykle przydatna, gdy chcemy wynieść logikę budowania adresu z szablonu HTML do klasy naszego komponentu.

<a [routerLink]="targetUrlTree">
 Url Tree
</a>

Podsumowanie

Nawigacja jest fundamentem każdego projektu i znajomość konceptu nawigowania wykorzystywanego w naszym frameworku jest niezbędna do pisania dobrze działających i łatwych w utrzymaniu aplikacji. 

W tym artykule przybliżyliśmy różne sposoby nawigowania i potomnych funkcji wykorzystywanych zarówno w szablonach HTML, jak i w kodzie Typescript.Mam nadzieję, że nauczyłeś się czegoś nowego, a Twoje projekty będą korzystały tylko z najlepszych praktyk nawigacji.

Podziel się artykułem

Zapisz się na nasz newsletter

Dołącz do community Angular.love i bądź na bieżąco z trendami.