Как я могу загрузить угловые компоненты на странице в последовательности?

Моя проблема в следующем:

У меня есть страница с большой формой (+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(), тогда родитель узнает, что ребенок закончил. Надеюсь, это полезно.