ActivatedRoute не обновляет данные дочернего маршрута при изменении маршрута - PullRequest
1 голос
/ 03 ноября 2019

Я пытаюсь получить данные дочернего маршрута ('layout') из родительского компонента, используя ActivatedRoute. Я попробовал следующий пример, и я могу получить данные, которые я ищу, но только один раз. Во время изменения дочернего маршрута я не вижу обновленного значения «макета».

Маршруты

const routes: Routes = [
  {
    path: '',
    component: Layout1Component,
    children: [
      {
        path: '',
        redirectTo: 'home',
        pathMatch: 'full'
      },
      {
        path: 'home',
        loadChildren: './pages/analytics/analytics.module#AnalyticsModule',
        data: {
          layout: 'boxed'
        }
      },
      {
        path: 'files',
        loadChildren: './pages/files/files.module#FilesModule',
        data: {
          layout: 'full'
        }
      }
    ]
  }
];

Layout1Component

export class Layout1Component implements OnInit {
  constructor(private service: AppService, route: ActivatedRoute) {
    this.layout = route.snapshot.firstChild.data['layout'];

    route.url.subscribe(() => {
      console.log(route.snapshot.firstChild.data['layout']);
    });
  }
}

Я хочу, чтобы файл console.log печатался с обновленным 'Layout 'значение каждый раз, когда маршрут меняется.

Пожалуйста, помогите мне исправить это.

1 Ответ

1 голос
/ 04 ноября 2019

Насколько я понимаю, причина, по которой вы получаете данные только один раз, заключается в том, что ActivatedRoute получает url как BehaviorSubject при его создании.

function createActivatedRoute(c: ActivatedRouteSnapshot) {
  return new ActivatedRoute(
      new BehaviorSubject(c.url), new BehaviorSubject(c.params), new BehaviorSubject(c.queryParams),
      new BehaviorSubject(c.fragment), new BehaviorSubject(c.data), c.outlet, c.component, c);
}

Вот ссылка на приведенный выше фрагмент

Это означает, что при подписке вы получите только это первое сохраненное значение.

OneЧтобы решить эту проблему, используйте события маршрутизатора .

Предположим, у вас есть что-то вроде этого:

const routes: Route[] = [
  { 
    path: '', 
    component: HelloComponent,
    children: [
      {
        path: 'foo',
        loadChildren: () => import('path/to/foo').then(m => m.FooModule),
        data: {
          name: 'andrei'
        }
      },
      {
        path: 'bar',
        loadChildren: () => import('path/to/bar').then(m => m.BarModule),
        data: {
          name: 'john'
        }
      },
    ]
  },
]

Вот возможное решение:

 constructor (private router: Router, private route: ActivatedRoute) { }

 ngOnInit () {
    const routeEndEvent$ = this.router.events
      .pipe(
        filter(e => e instanceof NavigationEnd),
        tap(() => console.warn("END")),
    );

    this.router.events
      .pipe(
        filter(e => e instanceof ChildActivationEnd && e.snapshot.component === this.route.component),
        buffer(routeEndEvent$),
        map(([ev]) => (ev as ChildActivationEnd).snapshot.firstChild.data),
        takeUntil(this.ngUnsubscribe$)
      )
      .subscribe(childRoute => {
        console.log('childRoute', childRoute);
      })
  }
  • routeEndEvent$ - наблюдаемая, которая будет излучать только тогда, когда маршрут будет готов (NavigationEnd)

  • filter(e => e instanceof ChildActivationEnd && e.snapshot.component === this.route.component): после проверкиВ то время как события, генерируемые маршрутизатором, я достиг этого решения, чтобы определить, является ли компонент (HelloComponent) родительским (this.route.component) маршрута, который изменился (e.snapshot.component).

  • buffer(routeEndEvent$): мы хотим действовать только тогда, когда маршрутизатор достигнет своего конечного состояния (NavigationEnd). здесь вы можете узнать больше об операторе buffer

StackBlitz

...