Why we use route resolver in Angular?
Think about the scenario when you are using *ngIf="some condition"
and your logic is depending upon the length of the array.
In this situation you might get into the problem, because your data will come up after the component is ready.
Here route resolver come in handy, Angular’s Route resolver API gets the data before the component is ready. Your conditional statements will work smoothly with route resolver class.
Angular 16 Route Resolver Example
A data provider can be used with the router to resolve data during navigation. The router waits for the data to be resolved before the route is finally activated.
It’s a simple function type definition for a data provider.
type ResolveFn<T> = (route: ActivatedRouteSnapshot, state: RouterStateSnapshot) => Observable<T> | Promise<T> | T;
Set up Angular Project
Install the Angular CLI with below command.
npm install @angular/cli -g
Now, you have to install the brand new Angular project using below command.
ng new angular-demo
Angular CLI asks for your choices while setting up the project…
Would you like to add Angular routing?
Select y and Hit Enter.
Which stylesheet format would you like to use? (Use arrow keys)
Choose SCSS and hit Enter
Use command to navigate into the project directory:
cd angular-demo
Next, run command to create components:
ng g c components/home
ng g c components/users
Remove Angular TypeScript Errors
To get rid from the errors:
Property ‘xxxName’ comes from an index signature, so it must be accessed with [‘xxxName’]
This setting makes sure profound consistency between accessing a field via the “dot” (obj.key)
syntax, and “indexed” (obj["key"])
and the way which the property is declared in the type.
Without this flag, TypeScript will allow you to use the dot syntax to access fields which are not defined:
Make sure to set following properties to false in tsconfig.json file:
"compilerOptions": {
...
...
"strict": false,
"noPropertyAccessFromIndexSignature": false,
...
...
},
"angularCompilerOptions": {
"strictTemplates": false
}
How to resolve data from an API?
Let’s take a look at a real-life example next. We are going to get some data from a specific API. We have chosen JSON placeholder’s API as a data source.
Let’s take a look at our service below. We have made use of the new HttpClient as well.
Create service/ folder and users-list.service.ts file, then add the given code into the file.
import { Injectable } from '@angular/core';
import { HttpClient } from '@angular/common/http';
@Injectable({
providedIn: 'root'
})
export class UsersListService {
url = 'https://jsonplaceholder.typicode.com/users';
constructor(public http: HttpClient) { }
getUsers() {
return this.http.get(this.url);
}
}
You have to import HttpClientModule service in app.module.ts file:
import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { HomeComponent } from './components/home/home.component';
import { UsersComponent } from './components/users/users.component';
import { HttpClientModule } from '@angular/common/http';
@NgModule({
declarations: [
AppComponent,
HomeComponent,
UsersComponent
],
imports: [
BrowserModule,
AppRoutingModule,
HttpClientModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
Create Route Resolver Function in Angular
We are going to explore a simple route resolver function in angular using the ResolveFn API. The data will be fetched from JSON Placeholder’s Users API.
Routing happens right after fetching the data. We are going to design a simple resolver first.
We will create a fresh file to create a separate class meant for the resolver.
Create APP/resolvers/ folder, further create route.resolver.ts file.
Ensure that you have added the given code in the src/app/resolvers/route.resolver.ts file.
import { UsersListService } from './../service/users-list.service';
import {
ActivatedRouteSnapshot,
ResolveFn,
RouterStateSnapshot,
} from '@angular/router';
import { inject } from '@angular/core';
import { Observable, of } from 'rxjs';
import { map, catchError } from 'rxjs/operators';
export const RouteResolver: ResolveFn<any> = (
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot,
usersListService: UsersListService = inject(UsersListService)
): Observable<{}> =>
usersListService.getUsers().pipe(
catchError((err) => {
return of('No data' + err);
})
);
Here, in this case, we are returning an observable.
Add Route Resolver in Angular Route
Now it is time for us to make sure that the routing module has our resolver.
Update given code in the app-routing.module.ts file:
import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
// Components
import { HomeComponent } from './components/home/home.component';
import { UsersComponent } from './components/users/users.component';
// Route resolver array
import { RouteResolver } from './resolvers/route.resolver';
const routes: Routes = [
{
path: 'home',
pathMatch: 'full',
component: HomeComponent
},
{
path: 'users',
component: UsersComponent,
resolve: {
routeResolver: RouteResolver
},
},
{
path: '**',
redirectTo: '/',
pathMatch: 'full'
},
];
@NgModule({
imports: [RouterModule.forRoot(routes)],
exports: [RouterModule],
providers: []
})
export class AppRoutingModule { }
Notice we included the resolver into our route definition, that emits the data after processing the service.
Here the resolved data will be available along with the message key.
You can simply open the browsers console and read the message there.
Accessing Resolved Data in the Component
In order to access the resolved data we can also use the data property of ActivatedRoute service.
Update code in components/users/users.component.ts file:
import { Component, OnInit } from '@angular/core';
import { UsersListService } from './../../service/users-list.service';
import { ActivatedRoute } from '@angular/router';
@Component({
selector: 'app-users',
templateUrl: './users.component.html',
styleUrls: ['./users.component.scss']
})
export class UsersComponent implements OnInit {
Users: any = [];
constructor(
private usersListService: UsersListService,
private actRoute: ActivatedRoute
) { }
ngOnInit() {
// Can access route resolver data with ActivatedRoute route service
this.actRoute.data.subscribe(data => {
console.log('Check route resolver data')
console.log(data)
})
// Some other method :)
this.usersListService.getUsers().subscribe((data: {}) => {
this.Users = data;
})
}
}
Displaying resolved data in Angular HTML template.
<ul class="list">
<li *ngFor="let users of Users">{{users.name}}</li>
</ul>
Set Up Navigation Routes
In order to create render data through the resolved routes in Angular, we need to define the navigation links.
For that we have to open the app.component.ts file, here we can place the given code:
<h2>Angular Route Resolver Function Example</h2>
<ul class="list">
<li><a routerLink="home">Home</a></li>
<li><a routerLink="users">Users</a></li>
</ul>
<router-outlet></router-outlet>
The following command will start a development server that will compile your app.
ng serve --open
Now, your app is served on the browser, you have to open the console and look for the resolved data.
Conclusion
In this tutorial, we learned how to create a route resolver class or function in Angular. Not only but also, we assimilate the entire process on how to register route resolver in angular routes and fetch the resolved data through route resolver in Angular.
In Angular, a route resolver is a feature that helps you to get data or perform some operations before a route is activated. It ensures that the necessary data is available before the corresponding component is loaded, preventing any issues related to missing data.