1

I'm having issues with browser refresh on my Angular app. When I reload the page, either by refreshing the browser or typing a URL, the app always goes to the "/" route.

I've tried many things but none worked.

The problem happens either when I'm on a live mode (ng serve on a local dev) or on the production server.

Here is my nginx config :

server {
  listen 80;
  location / {
      root /usr/share/nginx/html;
      index index.html index.htm;
      try_files $uri $uri/ /index.html;
    }
  expires $expires;
  gzip  on;
}

Here is my app-routing.module.ts :

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { LoginComponent } from './components/login/login.component';
import { UserProfileComponent } from './components/user-profile/user-profile.component';

import { AuthGuard } from './guards/auth.guard';
import {DashboardComponent} from './components/dashboard/dashboard.component';
import {ProjectsComponent} from './components/projects/projects.component';
import {TeamComponent} from './components/team/team.component';
import {RentalsComponent} from './components/rentals/rentals.component';
import {MessagesComponent} from './components/messages/messages.component';
import {SettingsComponent} from './components/settings/settings.component';
import {RouteconfigGuard} from './guards/routeconfig.guard';
import {ProjectAddComponent} from './components/projects/project-add/project-add.component';
import {TeamAddComponent} from './components/team/team-add/team-add.component';
// tslint:disable-next-line:max-line-length
import {SettingsCustomFieldsEditComponent} from './components/settings/settings-custom-fields/settings-custom-fields-edit/settings-custom-fields-edit.component';

const routes: Routes = [
  { path: '', redirectTo: '/login', pathMatch: 'full'},
  { path: 'login', component: LoginComponent},
  { path: 'testroute', component: SettingsComponent},
  { path: 'profile', component: UserProfileComponent, canActivate: [AuthGuard] },
  { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },
  { path: 'projects', component: ProjectsComponent, canActivate: [AuthGuard] },
  { path: 'team', component: TeamComponent, canActivate: [AuthGuard, RouteconfigGuard] },
  { path: 'team/add', component: TeamAddComponent, canActivate: [AuthGuard] },
  { path: 'team/edit/:id', component: TeamAddComponent, canActivate: [AuthGuard] },
  { path: 'rentals', component: RentalsComponent, canActivate: [AuthGuard] },
  { path: 'messages', component: MessagesComponent, canActivate: [AuthGuard] },
  { path: 'settings', component: SettingsComponent, canActivate: [AuthGuard] },
  { path: 'projects/add', component: ProjectAddComponent, canActivate: [AuthGuard] },
  { path: 'project/edit/:id', component: ProjectAddComponent, canActivate: [AuthGuard] },
  { path: 'project/edit/:id/:tab', component: ProjectAddComponent, canActivate: [AuthGuard] },
  { path: 'settings/custom-fields/:field', component: SettingsCustomFieldsEditComponent, canActivate: [AuthGuard] },
];

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

Here is my AuthGuard file :

import { Injectable } from '@angular/core';
import { CanActivate, ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from '../services/auth.service';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate {

  constructor(
    public authService: AuthService,
    public router: Router
  ) { }

  canActivate(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean> | Promise<boolean> | boolean {
    if (this.authService.isLoggedIn !== true) {
      this.router.navigate(['/']);
    }
    return true;
  }

}

And here is my auth.service file :

import {Injectable} from '@angular/core';
import {BehaviorSubject} from 'rxjs';
import {HttpClient} from '@angular/common/http';
import {Router} from '@angular/router';
import {environment as env} from '../../environments/environment';
import {LoaderService} from './loader.service';
import {MenuService} from './menu.service';
import {TokenService} from './token.service';

@Injectable({
  providedIn: 'root'
})

export class AuthService {
  signInEndpoint = env.mainApiEndpoint + '/login';
  badCredentials = new BehaviorSubject<boolean>(false);
  userLogged = new BehaviorSubject<boolean>(false);

  constructor(
    private http: HttpClient,
    public router: Router,
    public loaderService: LoaderService,
    public menuService: MenuService,
    public tokenService: TokenService
  ) {
  }

  // Sign-in
  signIn(user) {
    this.loaderService.show();
    this.badCredentials.next(false);
    return this.http.post<any>(this.signInEndpoint, user)
      .subscribe(
        (res) => this.manageLoginSuccess(res),
        (err) => this.setInvalidCredentials(err)
      );
  }

  manageLoginSuccess(res: any) {
    this.tokenService.setToken(res.token);
    this.userLogged.next(true);
    this.loaderService.hide();
    this.router.navigate([this.menuService.homepage]);
  }

  setInvalidCredentials(err) {
    this.loaderService.hide();
    this.badCredentials.next(true);
  }

  get isLoggedIn(): boolean {
    const authToken = this.tokenService.getToken();
    const isLogged = authToken !== null;
    if (isLogged) {
      this.userLogged.next(true);
    }
    return isLogged;
  }

  doLogout() {
    const removeToken = this.tokenService.removeToken();
    if (removeToken == null) {
      this.userLogged.next(false);
      this.router.navigate(['login']);
    }
  }
}

I've tried to change the canActivate implementation so that it always returns true and it didn't work. Even if I remove the call to canActivate on the routes files, it doesn't work neither. If I go to /testroute (as defined in the routes), it doesn't work.

What did I do wrong ?

Thank you so much for you help !

  • Please try adding an extra route at the top: `{ path: 'undefined', redirectTo: '/login', pathMatch: 'full' },` – ruth May 14 '20 at 13:55

1 Answers1

0

Try changing this (the order of the paths is important):

const routes: Routes = [
  { path: 'login', component: LoginComponent},
  { path: 'testroute', component: SettingsComponent},
  { path: 'profile', component: UserProfileComponent, canActivate: [AuthGuard] },
  { path: 'dashboard', component: DashboardComponent, canActivate: [AuthGuard] },
  { path: 'projects', component: ProjectsComponent, canActivate: [AuthGuard] },
  { path: 'team', component: TeamComponent, canActivate: [AuthGuard, RouteconfigGuard] },
  { path: 'team/add', component: TeamAddComponent, canActivate: [AuthGuard] },
  { path: 'team/edit/:id', component: TeamAddComponent, canActivate: [AuthGuard] },
  { path: 'rentals', component: RentalsComponent, canActivate: [AuthGuard] },
  { path: 'messages', component: MessagesComponent, canActivate: [AuthGuard] },
  { path: 'settings', component: SettingsComponent, canActivate: [AuthGuard] },
  { path: 'projects/add', component: ProjectAddComponent, canActivate: [AuthGuard] },
  { path: 'project/edit/:id', component: ProjectAddComponent, canActivate: [AuthGuard] },
  { path: 'project/edit/:id/:tab', component: ProjectAddComponent, canActivate: [AuthGuard] },
  { path: 'settings/custom-fields/:field', component: SettingsCustomFieldsEditComponent, canActivate: [AuthGuard] },
  { path: '', redirectTo: '/login', pathMatch: 'full'}

];

Documentation:
https://angular.io/guide/router#setting-up-redirects

Luciano
  • 450
  • 1
  • 7
  • 17