Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using Router in services in Angular 4

Tags:

angular

I've been using Angular 2/4 for about a year now and I keep returning to this dilemma whether injecting Router into service can be considered as a bad practice?

This is more architectural question. I believe there's no exact answer for it, but I want to hear your opinion. So here are 2 examples.

  1. Consider the next code. Imagine we have some component and we want to redirect user to specific route after some action, e.g. user added a new entity and we want to redirect him back to the grid.

component.ts

constructor(private router: Router) {}

someAction() {
  // Some code here
  this.router.navigate(['/grid']);
}

Here I think it's perfectly fine to use Router, because both Router and Component is UI layer.

  1. Now let's imagine we have auth.service.ts and it's responsible for authentication. We want to be able to logout user out of the application and we have logout() function to do that.

auth.service.ts

constructor(private router: Router) {}

logout() {
  // Cleanup token, storage, etc.
  this.router.navigate(['/login']);
}

So thinking architecturally:

  1. What do you think of such router usage inside the service?
  2. Do you think it's a valid approach?
  3. If not what do you suggest in this case?

I was thinking about putting eventEmitter on authService and subscribe to it inside app.component.ts for instance, but still not sure if it's better than having it in the service.

I appreciate any comments for this case. Thanks a lot!

EDIT

Another example: UI is a calendar with tasks.

There's a service that handles all data-flow and provides data for the calendar. Calendar itself doesn't ask for the data, instead it subscribes to the data change from the service.

Now I need to route user to a different screen from this calendar. Imagine user clicks next week/month/year.

This data stored in the route URL so user can stay on the same day after page refresh, but calendar component doesn't know about the days/weeks/months.

They are incapsulated inside the service. So will you use router in service in this case?

like image 273
Vitalii Chmovzh Avatar asked Nov 03 '17 14:11

Vitalii Chmovzh


People also ask

Can we use router in service Angular?

@angular/routerlink. Implements the Angular Router service , which enables navigation from one view to the next as users perform application tasks.

Is router mandatory for all applications in Angular?

simple answer is, no. It is not mandatory to have routes defined on every component you create.

How many instance of the router service should a routed Angular application have?

A routed Angular application has one singleton instance of the Router service. When the browser's URL changes, that router looks for a corresponding Route from which it can determine the component to display.


1 Answers

TL;DR: Its always better to do it from the component, since you can see where are the moving parts, wether in a service it can be done, but it is hard to identify as you will always check first the component.


You can use Guards for that purpose and interceptors, i've added an error interceptor like the following, to route to logout when i get a 401:

import { Injectable } from '@angular/core';
import { HttpEvent, HttpErrorResponse, HttpInterceptor, HttpHandler, HttpRequest } from '@angular/common/http';
import { Router } from '@angular/router';
import { Observable } from 'rxjs/Observable';
import 'rxjs/add/observable/throw';
import 'rxjs/add/operator/catch';

@Injectable()
export class ErrorInterceptor implements HttpInterceptor {
  constructor(private router: Router) {}

  intercept(req: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
    return next.handle(req).catch(
      (err: HttpErrorResponse) => {
        if (this.router.url !== '/login' && err.status === 401) {
          this.router.navigate(['/logout']);
        }
        return Observable.throw(err);
      }
    );
  }
}

Provide it in your app.module or in my case i've created a core.module for all the singletons to keep clean my app.module

{
  provide: HTTP_INTERCEPTORS,
  useClass: ErrorInterceptor,
  multi: true
}

With something like this you don't have to put routing in a service, you will get a 401 from your api when token is invalid.

You might have to work out a bit this code, tried to be as generic as possible.

like image 181
Sonicd300 Avatar answered Oct 03 '22 22:10

Sonicd300