angular / angular

Deliver web apps with confidence 🚀
https://angular.dev
MIT License
96.3k stars 25.54k forks source link

Outlet not activated, at run, refresh, or sometimes errors #31531

Closed deadmann closed 4 years ago

deadmann commented 5 years ago

🐞 bug report

Affected Package

"@angular/router": "~7.2.0",

Is this a regression?

I'm using the above version, and since i search a lot and non seem to be having same issue, i stop the search in case to do rest of things, but i really want to get rid of it

Description

Note: I had this issue from begin right after i create auth service and my first guard (auth guard)...

Sometimes, not all the times, when i open the website, either locally or on server, i face the error

ERROR Error: Uncaught (in promise): Error: Outlet is not activated
Error: Outlet is not activated
    at RouterOutlet.get [as component] (router.js:5013)
    at getRouteGuards (router.js:2922)
    at router.js:2885
    at Array.forEach (<anonymous>)
    at getChildRouteGuards (router.js:2884)
    at getAllRouteGuards (router.js:2854)
    at MapSubscriber.project (router.js:3907)
    at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (map.js:35)
    at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
    at TapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/tap.js.TapSubscriber._next (tap.js:51)
    at resolvePromise (zone.js:831)
    at resolvePromise (zone.js:788)
    at zone.js:892
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
    at Object.onInvokeTask (core.js:17280)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
    at drainMicroTaskQueue (zone.js:601)
    at ZoneTask.push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask [as invoke] (zone.js:502)
    at invokeTask (zone.js:1744)

this can either be on changin route, having error, or mostly when i refresh or open new page. the issue mostly resolve when i try to open pages without guards ... not all the time, not same page work all the time.

🔬 Minimal Reproduction

I'm not sure if it's possible to create it because there are a lot going out there (authentication, and guards and stuff), but here's my website: ashiane.house

If StackBlitz is not suitable for reproduction of your issue, please create a minimal GitHub repository with the reproduction of the issue. A good way to make a minimal reproduction is to create a new app via ng new repro-app and add the minimum possible code to show the problem. Share the link to the repo below along with step-by-step instructions to reproduce the problem, as well as expected and actual behavior.

Issues that don't have enough info and can't be reproduced will be closed.

You can read more about issue submission guidelines here: https://github.com/angular/angular/blob/master/CONTRIBUTING.md#-submitting-an-issue -->

🔥 Exception or Error


ERROR Error: Uncaught (in promise): Error: Outlet is not activated
Error: Outlet is not activated
    at RouterOutlet.get [as component] (router.js:5013)
    at getRouteGuards (router.js:2922)
    at router.js:2885
    at Array.forEach ()
    at getChildRouteGuards (router.js:2884)
    at getAllRouteGuards (router.js:2854)
    at MapSubscriber.project (router.js:3907)
    at MapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/map.js.MapSubscriber._next (map.js:35)
    at MapSubscriber.push../node_modules/rxjs/_esm5/internal/Subscriber.js.Subscriber.next (Subscriber.js:54)
    at TapSubscriber.push../node_modules/rxjs/_esm5/internal/operators/tap.js.TapSubscriber._next (tap.js:51)
    at resolvePromise (zone.js:831)
    at resolvePromise (zone.js:788)
    at zone.js:892
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:423)
    at Object.onInvokeTask (core.js:17280)
    at ZoneDelegate.push../node_modules/zone.js/dist/zone.js.ZoneDelegate.invokeTask (zone.js:422)
    at Zone.push../node_modules/zone.js/dist/zone.js.Zone.runTask (zone.js:195)
    at drainMicroTaskQueue (zone.js:601)
    at ZoneTask.push../node_modules/zone.js/dist/zone.js.ZoneTask.invokeTask [as invoke] (zone.js:502)
    at invokeTask (zone.js:1744)

🌍 Your Environment

Angular Version:


Your global Angular CLI version (7.3.8) is greater than your local
version (7.3.1). The local Angular CLI version is used.

I build the project for first time inside company PC, That's 7.3.1, but i have the same issue even if i build with that

Anything else relevant? Not Sure

Guard Codes:

import { Injectable } from '@angular/core';
import { CanActivate, CanActivateChild, CanLoad, Route, UrlSegment,
         ActivatedRouteSnapshot, RouterStateSnapshot, UrlTree, Router } from '@angular/router';
import { Observable } from 'rxjs';
import { AuthService } from '../_services/auth.service';
import { AlertifyService } from '../_services/alertify.service';

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

  constructor(private authService: AuthService, private router: Router, private alertify: AlertifyService) {}

  canActivate(
    /* next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot */): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    // return true;
    if (this.authService.loggedIn()) {
      return true;
    }
    this.alertify.error('You need to be logged in to access this area');
    this.router.navigate(['/home']);
    return false;
  }
  canActivateChild(
    next: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): Observable<boolean | UrlTree> | Promise<boolean | UrlTree> | boolean | UrlTree {
    return true;
  }
  canLoad(
    route: Route,
    segments: UrlSegment[]): Observable<boolean> | Promise<boolean> | boolean {
    return true;
  }
}

router codes:

import { NgModule } from '@angular/core';
import { Routes, RouterModule } from '@angular/router';
import { HomeComponent } from './home/home.component';
import { NestListComponent } from './nests/nest-list/nest-list.component';
import { AuthGuard } from './_guards/auth.guard';
import { NestDetailComponent } from './nests/nest-detail/nest-detail.component';
import { NestDetailResolver } from './_resolvers/nest-detail.resolver';
import { NestListResolver } from './_resolvers/nest-list.resolver';
import { UserEditComponent } from './users/user-edit/user-edit.component';
import { UserEditResolver } from './_resolvers/user-edit.resolver';
import { PreventUnsavedChanges } from './_guards/prevent-unsaved-changes.guard';
import { ValueComponent } from './value/value.component';
import { ManageNestListResolver } from './_resolvers/manage-nest-list.resolver';
import { ManageNestListComponent } from './nests/manage-nest-list/manage-nest-list.component';
import { ManageNestInsertComponent } from './nests/manage-nest-insert/manage-nest-insert.component';
import { ManageNestEditComponent } from './nests/manage-nest-edit/manage-nest-edit.component';
import { ManageNestDetailComponent } from './nests/manage-nest-detail/manage-nest-detail.component';
import { TestPageComponent } from './test-page/test-page.component';
import { CountryListResolver } from './_resolvers/country-list.resolver';
import { FacilityListResolver } from './_resolvers/facility-list.resolver';
import { AmenityListResolver } from './_resolvers/amenity-list.resolver';
import { RoomTypeListResolver } from './_resolvers/room-type-list.resolver';

const routes: Routes = [
  { path: 'home', component: HomeComponent },
  { path: 'links', component: ValueComponent },

  { path: 'nests', component: NestListComponent, resolve: {nests: NestListResolver} },
  { path: 'nests/:id', component: NestDetailComponent, resolve: {nest: NestDetailResolver} },

  // { path: 'properties', component: PropertyListComponent, canActivate: [AuthGuard] },
  { // if it doesn't match home, will fall to this category, and match the *empty* path...
    path: '',
    runGuardsAndResolvers: 'always', // mean it apply to this dummy route and children as well
    canActivate: [AuthGuard],
    children: [
      { path: 'manage/user/edit', component: UserEditComponent,
        resolve: {
          countries: CountryListResolver,
          user: UserEditResolver
        }, canDeactivate: [PreventUnsavedChanges] },
      { path: 'manage/nests', component: ManageNestListComponent,
        resolve: {nests: ManageNestListResolver} },
      { path: 'manage/nests/insert', component: ManageNestInsertComponent,
        resolve: {
          countries: CountryListResolver,
          facilities: FacilityListResolver,
          amenities: AmenityListResolver,
          roomTypes: RoomTypeListResolver
        },
        canDeactivate: [PreventUnsavedChanges] },
      { path: 'manage/nests/edit/:id', component: ManageNestEditComponent,
        resolve: {/** Extra Data to fill forms */}, canDeactivate: [PreventUnsavedChanges] },
      { path: 'manage/nests/detail/:id', component: ManageNestDetailComponent,
        resolve: {/** Extra Data to fill forms */} },
      // { path: 'nests/:id', component: NestDetailComponent, resolve: {nest: NestDetailResolver} }
    ]
  },
  { path: 'test-page', component: TestPageComponent },
  { path: '**', redirectTo: 'home', pathMatch: 'full' }
];

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

Auth Service

import { LoginVM } from './../../_models/dto/user/loginVM';
import { environment } from 'src/environments/environment';
import { Injectable } from '@angular/core';
import { HttpClient, HttpHeaders } from '@angular/common/http';
import { JwtHelperService } from '@auth0/angular-jwt';
import { map } from 'rxjs/operators';
import { IToken } from 'src/_models/internal/IToken';
import { UserVM } from 'src/_models/dto/user/userVM';
import { ModelHelper } from 'src/_utility/modelHelper';
import { BehaviorSubject } from 'rxjs';
import { ImageInfo } from 'src/_models/entities/fragment/imageInfo';
import { UserRegisterVM } from 'src/_models/dto/user/userRegisterVM';

@Injectable({
  providedIn: 'root'
})
export class AuthService {
  baseUrl = environment.apiUrl + 'account/';
  userToken: any;

  decodedToken: any;
  currentUser: UserVM;
  jwtHelper = new JwtHelperService();

  /** strong typed version of decodedToken */
  public get TokenObject(): IToken {
    return this.decodedToken as IToken;
  }

  constructor(private http: HttpClient) { }

  changeMemberPhoto(photos: ImageInfo[]) {
    this.currentUser.profilePictures = photos;
    localStorage.setItem('user', JSON.stringify(this.currentUser));
  }

  login(model: LoginVM) {
    // localStorage.removeItem('token');

    return this.http.post<JwtUser>(this.baseUrl + 'jwt-login' , model, this.requestOptions())
    .pipe(
      map(user => {
        if (user && user.token) {
          localStorage.setItem('token', user.token);
          localStorage.setItem('user', JSON.stringify(user.user));

          this.currentUser = ModelHelper.toUser(user.user);
          this.decodedToken = this.jwtHelper.decodeToken(user.token);

          // console.log(this.decodedToken);
          this.userToken = user.token;

          // this.changeMemberPhoto(this.currentUser.profilePictures); -> user contain images, so it's already set
        }

        return user;
      })
    );
  }

  loadTokenFromStorage() {
    const token = localStorage.getItem('token');
    const user: UserVM = ModelHelper.toUser(JSON.parse(localStorage.getItem('user')));
    if (token) {
      this.decodedToken = this.jwtHelper.decodeToken(token);
    }
    if (user) {
      this.currentUser = user;
      this.changeMemberPhoto(user.profilePictures);
    }
  }

  register(user: UserRegisterVM) {
    return this.http.post(this.baseUrl + 'register', user, this.requestOptions());
  }

  loggedIn() {
    const token = localStorage.getItem('token');
    return !this.jwtHelper.isTokenExpired(token);
  }

  logout() {
    this.userToken = null;
    this.currentUser = null;
    localStorage.removeItem('token');
    localStorage.removeItem('user');
  }

  private requestOptions() {
    const headers = new HttpHeaders({'Content-Type': 'application/json'});
    const options = { headers };
    return options;
  }
}

class JwtUser {
  public token: string;
  public user: UserVM;
}

packages:

{
  "name": "ashiane-app",
  "version": "0.0.0",
  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },
  "private": true,
  "dependencies": {
    "@angular/animations": "~7.2.0",
    "@angular/common": "~7.2.0",
    "@angular/compiler": "~7.2.0",
    "@angular/core": "~7.2.0",
    "@angular/forms": "~7.2.0",
    "@angular/platform-browser": "~7.2.0",
    "@angular/platform-browser-dynamic": "~7.2.0",
    "@angular/router": "~7.2.0",
    "@auth0/angular-jwt": "^2.1.0",
    "@fortawesome/fontawesome-free": "^5.9.0",
    "@ngx-translate/core": "^11.0.1",
    "@ngx-translate/http-loader": "^4.0.0",
    "alertifyjs": "^1.11.2",
    "bootstrap": "^4.3.1",
    "bootstrap4-toggle": "^3.4.0",
    "bootswatch": "^4.3.1",
    "core-js": "^2.5.4",
    "jalali-moment": "^3.3.1",
    "jquery": "^3.4.1",
    "leaflet": "^1.5.1",
    "linqts": "^1.12.5",
    "ng2-file-upload": "^1.3.0",
    "ngx-bootstrap": "^5.1.1",
    "ngx-gallery": "^5.7.0",
    "npm": "^6.9.2",
    "rxjs": "^6.3.3",
    "time-ago-pipe": "^1.3.2",
    "tslib": "^1.9.0",
    "underscore": "^1.9.1",
    "zone.js": "~0.8.26"
  },
  "devDependencies": {
    "@angular-devkit/build-angular": "~0.13.0",
    "@angular/cli": "~7.3.1",
    "@angular/compiler-cli": "~7.2.0",
    "@angular/language-service": "~7.2.0",
    "@types/jasmine": "~2.8.8",
    "@types/jasminewd2": "~2.0.3",
    "@types/jquery": "^3.3.30",
    "@types/node": "~8.9.4",
    "@types/underscore": "^1.8.18",
    "codelyzer": "~4.5.0",
    "jasmine-core": "~2.99.1",
    "jasmine-spec-reporter": "~4.2.1",
    "karma": "~3.1.1",
    "karma-chrome-launcher": "~2.2.0",
    "karma-coverage-istanbul-reporter": "~2.0.1",
    "karma-jasmine": "~1.1.2",
    "karma-jasmine-html-reporter": "^0.2.2",
    "protractor": "~5.4.0",
    "ts-node": "~7.0.0",
    "tslint": "~5.11.0",
    "typescript": "~3.2.2"
  }
}
deadmann commented 5 years ago

what's triage that it needs?

maxime1992 commented 5 years ago

I've got that issue too, absolutely no idea how to solve it.

I've tried to apply patches for the following:

https://github.com/angular/angular/pull/27262/files https://github.com/angular/angular/pull/20712/files https://github.com/angular/angular/pull/20712#issuecomment-433001509

None of those worked :sweat:

If anyone has any way of fixing that please let us know :pray:

deadmann commented 5 years ago

it seem the issue appear mostly when working locally :/ i'm not sure, i'm in middle of moving to another city, and some project at workplace..., and i got lost track of everything i was doing

atscott commented 4 years ago

Could someone provide a minimal reproduction of this in a GitHub repo with steps to reproduce?

atscott commented 4 years ago

Closing as duplicate of #39030

angular-automatic-lock-bot[bot] commented 4 years ago

This issue has been automatically locked due to inactivity. Please file a new issue if you are encountering a similar or related problem.

Read more about our automatic conversation locking policy.

This action has been performed automatically by a bot.