Resolvers in Angular

Resolver

Resolvers is used to provide data, before activating route, in brief, force the application to show the view only after loading the data. For easier understanding I will show it on the example.

Example of use:

I have a basic value model and I want to display it in the view.

export class Value {
    id: number;
    name: string;
}

Service for retrieving value from API with passing id parameter in URL.

  getValue() {
    this.valueService.getValue(+this.route.snapshot.params['id']).subscribe((value: Value) => {
      this.value = value;
    });
  }

Simple view.

<strong class="text-center">
  <p>Value:</p>
  <p>{{value.Name}}</p>
  <p>{{value.Id}}</p>
</strong>

After redirect to http://localhost:4200/value/1, we get error in console.

But our view loaded correctly. This happens because as I mentioned earlier when rendering the view component value , there is no model to display yet. To fix the error, we can use “elvis” operators.

<strong class="text-center">
  <p>Value:</p>
  <p>{{value?.Name}}</p>
  <p>{{value?.Id}}</p>
</strong>

It solves our error, however it is not recommended to use it often.

So the resolvers come here for help.

To use the resolver, I need to write a service that implements the interface resolve. The resolve method can take two parameters, ActivatedRouteSnapshot and RouterStateSnapshot.

Example of the resolver implementation:

@Injectable()
export class ValueResolver implements Resolve<string> {
    constructor(private valueService: ValueService, private router: Router) { }

    resolve(route: ActivatedRouteSnapshot): Observable<string> {
        return this.valueService.getValue(route.params['id']).pipe(
            catchError(error => {
                console.log('Error');
                this.router.navigate(['/home']);
                return of(null);
            })
        );
    }
}

* return of

Now I need to register it in app.module.ts in providers.

@NgModule({
...
   providers: [
      ValueResolver
   ],
...
})

Then pass the resolver in routing.

const routes: Routes = [
...
  { path: 'value/:id', component: ValueComponent, resolve: { value : ValueResolver } },
...
];

The ActivatedRoute interface gives us access to the ActivatedRouteSnapshot snapshot. It has access to a data object that contains data received from (in our case) resolver.

Let’s use the fact that our resolver returns the object observer and subscribe to it.

  ngOnInit() {
    this.route.data.subscribe(result => {
      this.value = result['value'];
    });
  }

We refer to the ‘value’ properity because that’s how I set it up in routing.

After changing the view

<strong class="text-center">
  <p>Value:</p>
  <p>{{value.Name}}</p>
  <p>{{value.Id}}</p>
</strong>

everything loads correctly without any errors.

Code available on github.

 

Leave a Reply

Your email address will not be published. Required fields are marked *