Как я могу загрузить угловые компоненты на странице в последовательности?
Моя проблема в следующем:
У меня есть страница с большой формой (+100 входов). Эти входные данные разделены на разделы, и эти разделы разработаны как различные компоненты (для повторного использования). Итак, общий макет страницы примерно такой:
<div>
<form-section-a></form-section-a>
<form-section-b></form-section-b>
<form-section-c></form-section-c>
...
<form-section-z></form-section-z>
</div>
Обработка каждого раздела формы займет некоторое время, поскольку большинство входных данных представляют собой поля выбора материала, а необходимые данные необходимо загрузить из REST API и обработать.
В показанном выше макете angular попытается отобразить все разделы формы одновременно, следовательно, добавляя время обработки каждого раздела, что приведет к зависанию браузера.
Итак, мой план - загружать разделы один за другим. Есть ли рекомендуемый способ для достижения этой цели?
Я попытался написать структурную директиву для загрузки компонентов один за другим. Несмотря на то, что директива работает, я не могу узнать, когда компонент завершил свою внутреннюю обработку (возможно, ловушка AfterViewInit). Директива выглядит примерно так,
<div tcSequentialRenderer>
<form-section-a *tcIfPreviousBlockLoaded></form-section-a>
<form-section-b *tcIfPreviousBlockLoaded></form-section-b>
<form-section-c *tcIfPreviousBlockLoaded></form-section-c>
...
<form-section-z *tcIfPreviousBlockLoaded></form-section-z>
</div>
,
@Directive({selector: '[tcSequentialRenderer]'})
export class SequentialRendererDirective implements AfterViewInit {
@ContentChildren(IfPreviousBlockLoadedDirective) directives: QueryList<IfPreviousBlockLoadedDirective>;
ngAfterViewInit() {
// start from first item
if (this.directives.length > 0) {
this.directives.toArray()[0].show();
}
let directivesArray = this.directives.toArray();
for (let i = 1; i < directivesArray.length; i++) {
directivesArray[i - 1].done.subscribe(status => {
if (status) {
directivesArray[i].show();
}
});
}
}
}
,
@Directive({selector: '[tcIfPreviousBlockLoaded]'})
export class IfPreviousBlockLoadedDirective {
private isShown = false;
public done: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(false);
constructor(
private tplref: TemplateRef<any>,
private vcref: ViewContainerRef
) { }
public show(): void {
if (!this.isShown) {
this.vcref.createEmbeddedView(this.tplref);
this.isShown = true;
}
}
}
Если я могу как-то получить доступ к связанному компоненту из IfPreviousBlockLoadedDirective
этот метод будет работать без проблем.
Есть ли какие-либо предложения, чтобы это исправить, или есть какие-то другие способы добиться этого без изменения компонентов раздела формы?
ПРИМЕЧАНИЕ. Форма сечения может быть любой угловой компонент.
3 ответа
Лучшее возможное решение, которое я могу подумать, это иметь следующую архитектуру:
Step-manager (этот компонент будет обрабатывать вход и выход из каждого раздела формы)
- Step-manager также предоставит сервис, который будет доступен всем дочерним компонентам.
- Step-manager также может иметь такие вещи, как индикатор прогресса (Progress-bar)
- Менеджер шагов может реагировать на тему поведения в сервисе и переключаться между компонентами / различными шаблонами внутри компонента.
обслуживание
- Сервис может обрабатывать все виды взаимодействия компонентов.
- Служба будет содержать тему поведения, которая будет использоваться всеми дочерними компонентами для информирования диспетчера шагов о том, что либо была нажата кнопка "Назад", либо нажата следующая кнопка.
- Служба также будет иметь возможность выполнять все вызовы службы для каждой из данных ввода формы.
Child-компоненты
- Дочерние компоненты могут быть отдельными компонентами (не рекомендуется)
- Они могут быть разделены на различные разделы (например: 3 шага "Персональной информации" могут быть 1 компонентом, 5 шагов "Образовательной информации" могут быть 1 компонентом)(я рекомендую это)
- Каждый дочерний компонент будет иметь различные встроенные шаблоны, которые будут отображаться / скрываться на основе логических значений. (Все обрабатывается пошаговым менеджером)
Пожалуйста, дайте мне знать, если это имеет смысл.
Вы слишком далеко зашли так мало.
Используйте источники событий, связанные с AfterViewInit
крючки:
<div>
<form-section-a (viewLoaded)="displaySectionB = true"></form-section-a>
<form-section-b *ngIf="displaySectionB" (viewLoaded)="displaySectionC = true"></form-section-b>
</div>
@Output() viewLoaded = new EventEmitter();
ngAfterViewInit() { this.viewLoaded.next(true); }
Поскольку ваши компоненты зависят друг от друга, вам придется явно объявить условия.
Есть более продвинутые способы сделать это (например, используя массивы), но я уверен, что вы найдете способы сделать это самостоятельно!
Я думаю, что тема хорошая идея для вашего требования. На самом деле у меня есть 3 формы в моем приложении, и я использовал ion-modal-controller там. Простой пример ниже:
class OneService {
public formSubject: Subject<Object> = new Subject<Object>();
}
class ParentPage {
constructor(oneService: OneService ) {
this.oneService.formSubject.subscribe(nextStepComponentName => {
this.nextStep(nextStepComponentName);
});
}
nextStep(nextStepComponentName) {
switch nextStepComponentName:
case 'ChildComponentB':
//load it
break;
default:
this.cancel();
}
}
class ChildComponentA {
constructor(oneService: OneService ) {
}
save() {
//do save.subscribe and
this.oneService.formSubject.next('ChildComponentB');
}
}
после того, как ребенок вызовет subject.next(), тогда родитель узнает, что ребенок закончил. Надеюсь, это полезно.