如何按顺序在页面中加载角度分量?

时间:2018-11-19 10:37:16

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

我的问题情况如下,

我有一个大页面的页面(+100个输入)。这些输入分为多个部分,这些部分被开发为不同的组件(用于重用)。因此页面的总体布局是这样的,

id

每个表单部分将花费一些时间,因为大多数输入都是材料选择框,并且需要从REST API加载并处理必要的数据。

在上面显示的布局中,angular会尝试一次渲染所有表单部分,因此增加了每个部分的处理时间,这将导致浏览器冻结。

因此,我的计划是一个接一个地加载节。 有没有推荐的方法来实现这一目标?

我试图编写一个结构指令来依次加载组件。即使该指令有效,也无法得知组件何时完成其内部处理工作(可能是AfterViewInit挂钩)。该指令看起来像这样,

<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>

<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; } } } 访问关联的组件,则此方法将无缝运行。

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

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

3 个答案:

答案 0 :(得分:0)

你走得太远了。

使用绑定到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); }

由于组件之间相互依赖,因此必须明确声明条件。

有更高级的方法(例如,使用数组),但是我敢肯定,您会找到自己的方法!

答案 1 :(得分:0)

我认为最好的解决方案是采用以下架构:

步骤管理器(此组件将处理进入和退出每个表单部分的操作)

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

服务

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

子组件

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

请告诉我这是否合理。

答案 2 :(得分:0)

我认为主题是满足您要求的好主意。实际上,我的应用程序中有3种形式,并且在那里使用了离子模态控制器。下面是一个简单的示例:

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()之后,然后父母知道孩子完成了。希望对您有所帮助。