【问题标题】:How can I load angular components in a page in sequence?如何按顺序在页面中加载角度组件?
【发布时间】:2019-04-21 16:53:06
【问题描述】:

我的问题场景如下,

我有一个带有大表单的页面(+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 访问相关组件,此方法将无缝运行。

是否有解决此问题的建议,或者是否有任何其他方法可以在不更改表单部分组件的情况下实现此问题?

注意:表单部分可以是任何角度组件。

【问题讨论】:

    标签: angular angular-components angular-dynamic-components angular-component-life-cycle


    【解决方案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); }
    

    因为您的组件相互依赖,您必须明确声明条件。

    有更高级的方法可以做到这一点(例如使用数组),但我相信你会找到自己的方法!

    【讨论】:

    • 是的。那是我最后的选择。但我不希望更改任何现有组件,因为它们是在共享组件库中开发的。
    • 嗯,这将很难绑定钩子事件(如果你想知道你的视图何时被初始化,这基本上是你唯一的选择)......
    【解决方案2】:

    我能想到的最佳解决方案是拥有以下架构:

    Step-manager(该组件将处理进入和退出每个表单部分)

    • step-manager 还将提供一项服务,该服务将可用 到所有子组件。
    • Step-manager 还可以有进度指示器(Progress-bar)之类的东西
    • 步骤管理器可以对服务上的行为主体做出反应,并在组件/组件内的不同模板之间切换。

    服务

    • 该服务可以处理各种组件交互。
    • 该服务将包含一个行为主题,所有子组件都将使用该主题来通知步骤管理器按下了后退按钮或按下了下一步按钮。
    • 该服务还将能够为每个表单输入数据进行所有服务调用。

    子组件

    • 子组件可以是单独的组件(不推荐)
    • 它们可以分为不同的部分(例如:“个人信息”的3个步骤可以是1个组件,“教育信息”的5个步骤可以是1个组件)(我推荐这个)
    • 每个子组件都将嵌入不同的模板,这些模板将根据布尔值显示/隐藏。 (全部由分步经理处理)

    如果这有意义,请告诉我。

    【讨论】:

      【解决方案3】:

      我认为主题很适合您的要求。事实上,我的应用程序中有 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() 之后,父母知道孩子完成了。希望对您有所帮助。

      【讨论】:

        猜你喜欢
        • 2011-07-28
        • 1970-01-01
        • 2019-03-27
        • 1970-01-01
        • 2019-08-08
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多