Load data before loading Component in Angular

September 1, 2019
by Rahil Shaikh
  • featured

In some scenarios, you might want to load some data from an API or async call before you render your component. We can make use of the Angular resolver feature provided in Angular Router to achieve that.

In this Angular tutorial, we will use the route resolver to load some data and inject it into the component before rendering it.

Without saying a thing further let’s just start the implementation.

Note. We are using Angular 8 for this tutorial.

Setup

Start a new angular app …

ng new resolve-tutorial

Once the app is created let’s create a new component and also add routing.

ng g c dashboard
ng generate module app-routing --flat --module=app

This will generate a component named dashboard for us and the second command will add the routing module.

Now, let’s add our routes.

import { NgModule } from '@angular/core';
import { CommonModule } from '@angular/common';
import { Routes, RouterModule } from '@angular/router';
import { DashboardComponent } from './dashboard/dashboard.component';

const routes: Routes = [
  {
    path: 'dashboard',
    component: DashboardComponent
  },
  {
    path: '',
    redirectTo: 'dashboard',
    pathMatch: 'full'
  }
]

@NgModule({
  declarations: [],
  imports: [
    CommonModule,
    RouterModule.forRoot(routes)
  ],
  exports: [RouterModule]
})
export class AppRoutingModule { }

Finishing the basic setup by adding the AppRoutingModule to the imports of the main App Module and placing router-outlet in app.component.html

app.module.ts
...
..
imports: [
    ...,
    AppRoutingModule,
    ...,
  ],
..
...
app.component.html
<!--The content below is only a placeholder and can be replaced.-->
<div style="text-align:center">
  <h1>
    Welcome to resolve tutorial!
  </h1>
  <img width="300" alt="Angular Logo" src="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAyNTAgMjUwIj4KICAgIDxwYXRoIGZpbGw9IiNERDAwMzEiIGQ9Ik0xMjUgMzBMMzEuOSA2My4ybDE0LjIgMTIzLjFMMTI1IDIzMGw3OC45LTQzLjcgMTQuMi0xMjMuMXoiIC8+CiAgICA8cGF0aCBmaWxsPSIjQzMwMDJGIiBkPSJNMTI1IDMwdjIyLjItLjFWMjMwbDc4LjktNDMuNyAxNC4yLTEyMy4xTDEyNSAzMHoiIC8+CiAgICA8cGF0aCAgZmlsbD0iI0ZGRkZGRiIgZD0iTTEyNSA1Mi4xTDY2LjggMTgyLjZoMjEuN2wxMS43LTI5LjJoNDkuNGwxMS43IDI5LjJIMTgzTDEyNSA1Mi4xem0xNyA4My4zaC0zNGwxNy00MC45IDE3IDQwLjl6IiAvPgogIDwvc3ZnPg==">
</div>
<h2>Load Route ...</h2>
<router-outlet></router-outlet>

Run ng serve to see if everything is in place.

Using Resolve to Inject data

Now let’s create a service that would return us data asynchronously. We will use setTimeout function to simulate an asynchronous call to an API server.

data.service.ts
import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class DataService {
  user = {
    name: 'Mason',
    age: 19,
    profession: 'Footballer'
  }
  constructor() { }

  getData(): Observable<any>{
    return new Observable((o)=>{
      setTimeout(()=>{
        o.next(this.user);
      }, 1000)
    })
  }
}

Next, we will create a Data Resolver service which implements the interface Resolve.

data-resolver.service.ts
import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot, RouterStateSnapshot } from '@angular/router';
import { take, map } from 'rxjs/operators';

import { DataService } from './data.service';
import { Observable } from 'rxjs';
@Injectable({
  providedIn: 'root'
})
export class DataResolverService implements Resolve <Observable<any>>{

  constructor(private ds: DataService) { }

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot){
    return this.ds.getData().pipe(
      take(1),
      map(userdata => userdata)
    )
  }
}

This Resolver can be added to the route as shown below.

const routes: Routes = [
  {
    path: 'dashboard',
    component: DashboardComponent,
    resolve: {
      userdata: DataResolverService
    }
  },
  {
    path: '',
    redirectTo: 'dashboard',
    pathMatch: 'full'
  }
]

The key userdata which can be anything is important here as in our Dashboard component we will use the same key to access the resolved User’s Data. Let’s see that below…

dashboard.component.ts
import { Component, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';

@Component({
  selector: 'app-dashboard',
  templateUrl: './dashboard.component.html',
  styleUrls: ['./dashboard.component.css']
})
export class DashboardComponent implements OnInit {
  userdata: any;
  constructor(private route: ActivatedRoute) { }

  ngOnInit() {
    this.userdata = this.route.snapshot.data.userdata; // get data from resolver
  }

}

Now the user data should be available before the component instantiates.

2

2

Multiple Resolvers in Angular

Angular routers support multiple resolvers.

{
  path: 'dashboard',
  component: DashboardComponent,
  resolve: {
    userdata: DataResolverService,
    bar: Resolver2,
    // more resolves here...
  }
}

These resolvers resolve in parallel independent of each other. In the case where there are more than one Resolvers, Angular will load the component only when all of the Resolvers are resolved.

How to pass data from one resolve to another in Angular?

One of the common problems you might come up with is passing the data from 1st resolve to the next. As of at the time of writing this article, the feature is not yet supported by the Angular Router. There is an active feature PR running for that.

To get around this what you can do is, create a wrapper service which will pull all the data one after another and then pass that to resolve.

Code

You can find an example application that uses resolve on this link.

Conclusion

So we have seen how resolve can be of great use to prefetch data before loading the component in Angular. This is the right way to load any dependent data without which your component cannot load.

Keep Learning…

About

Engineer. Blogger. Thinker. Loves programming and working with emerging tech. We can also talk on Football, Gaming, World Politics, Monetary Systems.

Get notified on our new articles

Subscribe to get the latest on Node.js, Angular, Blockchain and more. We never spam!
First Name:
Email:

Leave a Comment