Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Handle errors in a Resolve service

Say I have a ValuesComponent that displays an array of Value in an HTML table.

// in value.ts
export class Value { ... }
// in values.component.ts
@Component(...)
export class ValuesComponent { ... }

Being a good programmer and all, I've created a different class that is responsible for providing values. Let's call it the ValuesService.

// in values.service.ts
@Injectable()
export class ValuesService
{
    public getValues(): Observable<Value[]>
    {
       ...
    }
}

Suppose that the service gets its values from a web service: /api/values

Now instead of injecting the service directly into my component, I want to let the Angular router pre-fetch the values before navigating to the component.

For that, I created a Resolve service class and plugged it into the router module.

// in values-resolver.service.ts
export class ValuesResolverService implements Resolve<Value[]> {
    constructor(private backend: ValuesService) {
    }

    public resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Value[]> {
        return this.backend.getValues();
    }
}
// In app.module.ts (in @NgModule())
imports: [
  RouterModule.forRoot([{
    path: 'values',
    component: ValuesComponent,
    resolve: { values: ValuesResolverService }
  }])
]
// In values.component.ts
public values: Value[];

constructor(private route: ActivatedRoute) {
}

ngOnInit() {
    this.values = route.data.values as Value[];
}

How am I doing so far? Good? Then where do I put my error handling for when ValuesService.getValues() fails? (connection error, internal server error, ...)

When a user tries to navigate to the /#/values route and an error occurs, I want to log the error to the console and stop navigation. Ideally, I'd like to redirect the user to the /#/error route (not shown in the example code).

like image 666
Steven Liekens Avatar asked Nov 08 '16 14:11

Steven Liekens


People also ask

How do you handle errors in angular service?

One traditional way of handling errors in Angular is to provide an ErrorHandler class. This class can be extended to create your own global error handler. This is also a useful way to handle all errors that occur, but is mostly useful for tracking error logs.

How do you handle error Express?

The simplest way of handling errors in Express applications is by putting the error handling logic in the individual route handler functions. We can either check for specific error conditions or use a try-catch block for intercepting the error condition before invoking the logic for handling the error.

What is resolve in routing?

ResolvelinkA data provider class can be used with the router to resolve data during navigation. The interface defines a resolve() method that is invoked right after the ResolveStart router event. The router waits for the data to be resolved before the route is finally activated.


1 Answers

In such a situation, the Service should handle the error, and redirect to the wanted route. The catch method should then return an empty Observable (for the resolve guard to resolve), while handling empty cases during within the resolve.

Something like this

export class ValuesService {
    constructor(private http:Http, private router:Router) {}

    getValue() {
       this.http.get('/some/url').map((response:Response) => {
           // Map your response to a model here
       }).catch((response:Response) => {
           // Handler case for different status
           this.router.navigate(['/error']);
           return Observable.empty();
       })
    }
}

And the guard to be like the following

export class ValueResolveGuard implements Resolve<Value[]> {

    constructor(private valueService:ValueService) {}

    resolve() { // You don't need the route & state if you're not gonna use them
        this.valueService.getValue().toPromise().then((values:Values[]) => {
            if (!values) { // For the Observable.empty() case
                // return some default stuff
            }
            return values;
        })
    }
}

Alternatively, if you want to specifically return an observable (shouldn't make any difference in this case, since the resolve guard, accepts both an observable and a promise), you can do something like this.

 this.valueService.getValue().first().catch({} => { 
      // return some default value.
 });

Notice that first() is required, so that the observable returned would be a terminated observable, otherwise the resolve guard wouldn't resolve. The catch is needed because a first() call on an empty observable would throw an error.

like image 145
JeanPaul A. Avatar answered Oct 09 '22 06:10

JeanPaul A.