Благодаря Гюнтер Zöchbauer answer (см. комментарии), я заработал.
Как я understant, детектор изменения углового работает так:
cd.detectChanges(); // Detects changes but doesn't update view.
cd.markForCheck(); // Marks view for check but doesn't detect changes.
Так что вам нужно использовать как для того, чтобы быстро восстановить все дерево компонентов.
1. Шаблон изменения
Для того, чтобы перезарядить все приложение, нам нужно, чтобы скрыть и показать все дерево компонентов, поэтому нам нужно обернуть все в app.component.html
в ng-container
:
<ng-container *ngIf="!reloading">
<header></header>
<main>
<router-outlet></router-outlet>
</main>
<footer></footer>
</ng-container>
ng-container
лучше div, потому что он не отображает никаких элементов.
Для поддержки асинхронной, мы можем сделать что-то вроде этого:
<ng-container *ngIf="!(reloading$ | async)"> ... </ng-container>
reloading: boolean
и reloading$: Observable<boolean>
здесь указывает на то, что компонент в настоящее время перезагружается.
В компоненте у меня есть LocaleService
который имеет language$
наблюдаемый. Я буду слушать измененное языковое событие и выполнить перезагрузку приложения.
2.Синхронизировать пример
export class AppComponent implements OnInit {
reloading: boolean;
constructor(
private cd: ChangeDetectorRef,
private locale: LocaleService) {
this.reloading = false;
}
ngOnInit() {
this.locale.language$.subscribe(_ => {
this.reloading = true;
this.cd.detectChanges();
this.reloading = false;
this.cd.detectChanges();
this.cd.markForCheck();
});
}
}
3. Aync пример
export class AppComponent implements OnInit {
reloading: BehaviorSubject<boolean>;
get reloading$(): Observable<boolean> {
return this.reloading.asObservable();
}
constructor(
private cd: ChangeDetectorRef, // We still have to use it.
private locale: LocaleService) {
this.reloading = new BehaviorSubject<boolean>(false);
}
ngOnInit() {
this.locale.language$.subscribe(_ => {
this.reloading.next(true);
this.cd.detectChanges();
this.reloading.next(false);
this.cd.detectChanges();
});
}
}
Мы не должны cd.markForChanges()
сейчас, но мы все еще должны сказать, детектор для обнаружения изменения.
4. Маршрутизатор
маршрутизатор не работает, как ожидалось. При повторной загрузке приложения таким образом router-outlet
будет пустым. Я еще не разрешил эту проблему, и переход на тот же маршрут может быть болезненным, потому что это означает, что любые изменения, внесенные пользователем в формы, например, будут изменены и потеряны.
5. OnInit
Вы должны использовать OnInit крюк. Если вы попытаетесь вызвать cd.detectChanges() внутри конструктора, вы получите сообщение об ошибке, поскольку угловой компонент еще не будет создан, но вы попытаетесь обнаружить изменения на нем.
Теперь вы можете подумать, что я подписываюсь на другую службу в конструкторе, и моя подписка будет срабатывать только после полной инициализации компонента. Но дело в том, что вы не знаете, как работает сервис! Если, например, он просто испускает значение Observable.of('en')
- вы получите сообщение об ошибке, потому что, как только вы подписались - первый элемент испустит немедленно, пока компонент все еще не инициализирован.
У моей LocaleService
есть такая же проблема: предметом наблюдения является BehaviorSubject
. BehaviorSubject
является субъектом rxjs, который испускает по умолчанию значение сразу сразу после подписания. Поэтому, как только вы пишете this.locale.language$.subscribe(...)
- подписка сразу срабатывает хотя бы один раз, и только после этого вы будете ждать изменения языка.
Вы можете использовать ' '. Он был добавлен, чтобы иметь возможность использовать более распространенный синтаксис, но все же с тем же поведением, что и элемент ''. –
Обновлено с помощью ''. –
EwanCoder
AFAIK 'cd.detectChanges(); запускает обнаружение изменений немедленно и синхронно и' cd.markForCheck(); 'запускает обнаружение изменений для этого компонента в следующем цикле обнаружения изменений (несколько позже). –