Exziled
Exziled

Reputation: 493

Angular6 app logic that runs on every page

I'm converting from AngularJS to Angular6 currently but am not finding any solutions to this question.

Where is it best practice to keep app logic that needs to run on every page that the angular app loads on?

Example logic is logging a user in based on a cookie stored on the machine. Where should I put this logic to check for the cookie and log the user in?

The best place I've seen thus far is in app.component.ts. I used to accomplish this in AngularJS via loading a GlobalController on all pages and then loading a HomepageController etc that would load for the specific "partial" that was plugged into the page.

e/ To clarify, this was just an example and isn't the ONLY business logic I need to run on every page. I need to trigger backend requests every ~10 seconds that check timers on the server (for app timeouts/etc).

Upvotes: 3

Views: 952

Answers (5)

alexc
alexc

Reputation: 208

Here's an example of solving your particular problem by using an AuthenticationService and a CanActivate route guard. The below Guard can be bound to whatever route (page) you please, be it one or all of them.

@Injectable()
class AuthenticationService {
  constructor () { }

  isLoggedIn() {
    // check your cookie logic here
  }
}

@Injectable()
class AuthenticationGuard implements CanActivate {

  constructor(private authenticationService: AuthenticationService, private router: Router) { }

  canActivate(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<boolean> {
    return this.authenticationService.isLoggedIn()
      .pipe(
        tap(loggedIn => {
          if (!loggedIn) {
            this.router.navigate(['/login'], {
              queryParams: {
                nextUrl: state.url
              }
            });
          }
        })
      );
  }
}

@NgModule({
  ...
  imports: [
    RouterModule.forRoot([
      { path: 'dummyRoute/', loadChildren: './components/dummyModule/dummy.module#DummyModule', canActivate: [ AuthenticationGuard ] },
    ])
  ],
  ...
})
export class AppModule {}

While using AppComponent to run code on every page is a solution, I would only recommend it as a last resort. For the most part, Guards (used for authorising navigation steps), Resolvers (used for retrieving data required by the page prior load) and Interceptors (used to alter / filter HttpClient requests) used in conjunction with Services provide you with a more elegant way to solve these problems and keep your codebase neatly organised.

More on guards here https://angular.io/guide/router#guards.

A full example of an authentication guard implementation: https://angular.io/guide/router#canactivate-requiring-authentication

Upvotes: 0

Ryan E.
Ryan E.

Reputation: 1027

For authenticating Http requests you can you HttpInterceptors to append a token to each request for your API. Something like this ->

my-http.interceptor.ts

 @Injectable()
 export class MyHttpInterceptor implements HttpInterceptor {

   constructor() {}

      intercept(request: HttpRequest<any>, next: HttpHandler): Observable<HttpEvent<any>> {
         const token = 'my_token'; // retrieve token from your storage.
         const req = request.clone({
             setHeaders: {
               Authorization: `Bearer ${token}`
             }
           });

           return next.handle(req).do((event: HttpEvent<any>) => {
             // success
             if (event instanceof HttpResponse) {
             }
           }, (err: any) => {
             // failure
             if (err instanceof HttpErrorResponse) {
             }
           });
       }
 }

Then register your http interceptor on either your CoreModule or AppModule.

 providers: [
     { provide: HTTP_INTERCEPTORS, useClass: MyHttpInterceptor, multi: true}
 ]

RouteGuards can be used to block certain routes for any reason you want - User isn't authorized, User doesn't have the proper role to access, ect...

https://codecraft.tv/courses/angular/routing/router-guards/


If you want to execute logic on Route change you can listen in on the router.events.

How to detect a route change in Angular?


Edit: As other people in this thread pointed out, always put business logic in a service.

For a best practice angular app structure -> https://itnext.io/choosing-a-highly-scalable-folder-structure-in-angular-d987de65ec7

Upvotes: 1

rav3n6
rav3n6

Reputation: 27

I would use Angular service and i would call it from app.component

It Says

Services are a great way to share information among classes that don't know each other.

Upvotes: -1

Fateh Mohamed
Fateh Mohamed

Reputation: 21367

you can create an authentication service (auth.service.ts) in your app and make it singleton, that service will contain all auth operation like (login, logout, getProfile...) after that you can inject that service and use it everywhere in your app when needed.

i recommend that you separate your app into modules and create a module for authentication.

and for everything shared you can create a shared module that contains shared components, services, pipes, interceptors ...

Upvotes: 0

K. Ayoub
K. Ayoub

Reputation: 426

you should put that logic in the app.components.ts

import { Component } from "@angular/core";

@Component({
    selector: "app-root",
    templateUrl: "./app.component.html",
    styleUrls: ["./app.component.css"]
})
export class AppComponent {
    // here goes your logic
}

Upvotes: 1

Related Questions