Support us .Net Basics C# SQL ASP.NET Aarvi MVC Slides C# Programs Subscribe Download

Angular resolve guard

Suggested Videos
Part 51 - Angular query params | Text | Slides
Part 52 - Angular read query string parameters | Text | Slides
Part 53 - Create observable from array | Text | Slides

In this video we will discuss Angular resolve guard with an example. This is continuation to Part 53. Please watch Part 53 from Angular CRUD tutorial before proceeding.


At the moment, when you navigate to the LIST route, only a part of the page loads first and after 2 seconds when the data becomes available that's when the page is updated with employee list. 

You don't want to display a partial page to the user, while waiting for the data. Before we activate the LIST route and display the view template associated with the LIST route, we want to pre-fetch the data. Once the data is available, that's when we want to render the view template, so the end user does not see a partial page. 

So in short, we want to delay rendering the routed component view template until all necessary data have been fetched.


To pre-fetch data for a route we use a route resolver. A route resolver can be implemented as a function or a service. In this video, let's implement the route resolver as a service. In a later video, we will discuss how to implement it as a function.

The following are the steps to implement a route resolve guard

Step 1 : Implement the Route Resolver Service. Add a new file to the "employees" folder. Name it "employee-list-resolver.service.ts". Copy and paste the following code.

import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { Employee } from '../models/employee.model';
import { Observable } from 'rxjs/Observable';
import { Injectable } from '@angular/core';
import { EmployeeService } from './employee.service';

@Injectable()
// Implement the Resolve interface, as we are implementing a route resolve guard
// Resolve interface supports generics, so specify the type of data that this
// resolver returns using the generic parameter
export class EmployeeListResolverService implements Resolve<Employee[]> {
    // Inject the employeee service as we need it to retrieve employee data
    constructor(private _employeeService: EmployeeService) {
    }
    // Resolve interface contains the following one method for which we need to
    // provide implementation. This method calls EmployeeService & returns employee data
    resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Employee[]> {
        return this._employeeService.getEmployees();
    }
}

Step 2 : Register the Route Resolver Service. At the moment we only have one module in our application and that is the root module - AppModule in app.module.ts file.

import { EmployeeListResolverService } from './employees/employee-list-resolver.service';

@NgModule({
  declarations: [...
  ],
  imports: [...
  ],
  providers: [EmployeeListResolverService],
  bootstrap: [AppComponent]
})
export class AppModule {}

Step 3 : Add the Route Resolver Service to the route for which we want to pre-fetch data. In our case we want to add the EmployeeListResolverService on the LIST route. To do this use the resolve property of the route configuration as shown below. Notice, the value for resolve property is an object with a key and a value. The key is employeeList. You can name it anything you want. The value is the resolver service, which provides the employee data. When the angular router sees this configuration, it knows it has to prefect the employee list data, before it can activate the LIST route and display it's associated view template.

const appRoutes: Routes = [
  {
    path: 'list',
    component: ListEmployeesComponent,
    resolve: { employeeList: EmployeeListResolverService }
  },
  // other routes
];

Step 4 : Read the pre-fetched data from the ActivatedRoute. In our case, modify the code in ListEmployeesComponent class to read the data from the route. Since the route resolver service is prefetching the data, we do not need EmployeeService reference in this component anymore. So remove all the EmployeeService references from this component, including the import statement.

export class ListEmployeesComponent implements OnInit {
  // rest of the code
  constructor(private _employeeService: EmployeeService,
    private _router: Router,
    private _route: ActivatedRoute) {

    this.employees = this._route.snapshot.data['employeeList'];

    if (this._route.snapshot.queryParamMap.has('searchTerm')) {
      this.searchTerm = this._route.snapshot.queryParamMap.get('searchTerm');
    } else {
      this.filteredEmployees = this.employees;
    }
  }

  ngOnInit() {
  }
  // rest of the code
}

At this point, when we navigate to the LIST route, the angular router, first pre-fetches the data, before activating the route and rendering it's associated view template. At the moment, while we are waiting for the route resolver to fetch data, the end user does not have any visual clue indicating that the request is being processed. In our upcoming videos we will discuss, how to display loading...icon.

angular crud tutorial

2 comments:

  1. Is there any generic way to write resolver service for every component or we have to build resolver service for every screen ?

    ReplyDelete
  2. Hi Venkat, Thank You so much for your tutorials!
    Is there any specific reason we are reading the data in the constructor() instead of ngOnInit() life cycle hook like we were doing in the previous videos.

    ReplyDelete

It would be great if you can help share these free resources