angular: The behavior of ActivatedRoute's Observables are not documented (only emit when shallow equality check fails)

🐞 bug report

Description

I have two modules:

const routes: Routes = [
  { path: 'users', loadChildren: () => import('./modules/users/users.module').then(m => m.UsersModule) },
  { path: 'chats', loadChildren: () => import('./modules/chats/chats.module').then(m => m.ChatsModule) }
];

Those modules contains some routes with the resolvers. E.g:

users-routing.module.ts

const routes: Routes = [
  {
    path: '',
    component: UsersComponent,
    resolve: { 
      users: UsersResolver 
    },
    runGuardsAndResolvers: 'always', // <-- Resolver works fine, always
    children: [
      { path: 'create', component: UsersCreateComponent },
      { path: 'update/:token', resolve: { user: UserResolver }, component: UsersUpdateComponent },
      { path: 'details/:token', resolve: { user: UserResolver }, component: UsersDetailsComponent },
    ]
  },
];

users.resolver.ts

import { Injectable } from '@angular/core';
import { Resolve, ActivatedRouteSnapshot } from '@angular/router';
import { Observable } from 'rxjs';
import { take } from 'rxjs/operators';

import { UsersService } from '../services/users.service';

@Injectable({
  providedIn: 'root'
})
export class UsersResolver implements Resolve<any[]> {

  constructor(private usersService: UsersService) { }

  resolve(route: ActivatedRouteSnapshot): Observable<any[]> {
    return this.usersService.fetchUsers().pipe(take(1));
  }

}

When i navigate from the children path to the parent path e.g. /users, UsersResolver works fine, but the code listed below won’t works if a resolver returns an empty array:

users.component.ts

ngOnInit(): void {
    // Doesn't fired up when a resolver returns an empty data.users array
    // But if i have at least one object in the array, then this code works fine
    this.route.data.subscribe(data => {
      this.users = data.users;
      console.log(this.users);
    });
}

The important thing is that resolver sends requests to the server, but this.route.data.subscribe(...) still doesn’t works when resolver returns an empty array. A bug exists only between the parent <-> children navigation. Navigation between the modules and this.route.data.subscribe(...) with the resolvers works fine.

Minimal Reproduction

Thanks to @destus90: https://stackblitz.com/edit/angular-ivy-9ajhzu?file=src%2Fapp%2Fmodules%2Fusers.service.ts

My previous report, same problem: #37365

Expected behaviour

this.router.data.subscribe(...) should works if a resolver returns an empty array between the parent <-> children navigation.

🌍 Your Environment

Angular Version:


Angular CLI: 9.0.7
Node: 14.15.3
OS: linux x64

Angular: 
... 
Ivy Workspace: 

Package                      Version
------------------------------------------------------
@angular-devkit/architect    0.900.7
@angular-devkit/core         9.0.7
@angular-devkit/schematics   9.0.7
@schematics/angular          9.0.7
@schematics/update           0.900.7
rxjs                         6.5.3

About this issue

  • Original URL
  • State: closed
  • Created 3 years ago
  • Comments: 20 (7 by maintainers)

Commits related to this issue

Most upvoted comments

I found out that when a resolver returns the same value as in a previous call a subscriber for route.data is not notified. Once I return some Math.random() value, my subscription is activated and a returned value is printed when navigating between Parent <> Child routes. https://stackblitz.com/edit/angular-ivy-9ajhzu?file=src%2Fapp%2Fmodules%2Fusers.service.ts

I have many real-world projects on the angular and every time i’ve stopped with this behaviour.

Have you tried subscribing to the navigation events instead? This should unblock you - https://stackblitz.com/edit/angular-ivy-5wtfjy?file=src%2Fapp%2Fmodules%2Fusers.component.ts

@atscott I have next question: why emitter doesn’t check shallowEqual for the parent routes and do this for the children routes?

I’m not sure I follow this exactly. Is it shown in the reproduction? I would guess this is unrelated and actually has to do with component reuse or lack thereof.