Как я могу загрузить угловые компоненты на странице в последовательности? - PullRequest
0 голосов
/ 19 ноября 2018

Мой сценарий проблемы следующий:

У меня есть страница с большой формой (+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 ]

0 голосов
/ 19 ноября 2018

Лучшее возможное решение, которое я могу себе представить, это иметь следующую архитектуру:

Step-manager (Этот компонент будет обрабатывать вход и выход из каждого раздела формы)

  • Step-manager также предоставит услугу, которая будет доступна для всех дочерних компонентов.
  • Step-manager также может иметь такие вещи, как индикатор прогресса (Progress-bar)
  • Step-manager может реагировать на тему поведения в сервисе и переключаться между компонентами / различными шаблонами внутри компонента.

Услуги

  • Сервис может обрабатывать все виды взаимодействия компонентов.
  • Служба будет содержать тему поведения, которая будет использоваться всеми дочерними компонентами для информирования диспетчера шагов о том, что либо была нажата кнопка возврата, либо нажата следующая кнопка.
  • Служба также будет иметь возможность выполнять все вызовы службы для каждой из данных ввода формы.

Дети-компонента

  • Дочерние компоненты могут быть отдельными компонентами (не рекомендуется)
  • Они могут быть разделены на различные разделы (например, 3 шага «Персональной информации» могут быть 1 компонентом, 5 шагов «Образовательной информации» могут быть 1 компонентом) (я рекомендую это)
  • В каждый дочерний компонент будут встроены различные шаблоны, которые будут отображаться / скрываться в зависимости от логических значений. (Все обрабатывается пошаговым менеджером)

Пожалуйста, дайте мне знать, если это имеет смысл.

0 голосов
/ 19 ноября 2018

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

0 голосов
/ 19 ноября 2018

Вы слишком далеко зашли слишком мало.

Использовать источники событий, связанные с 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); }

Поскольку ваши компоненты зависят друг от друга, вам придется явно объявить условия.

Есть более продвинутые способы сделать это (например, используя массивы), но я уверен, что вы найдете способы сделать это самостоятельно!

...