递归动态Angular形式;从 Deeper Child 到 Root(Parent 组件)的 EmitEvent

Recursive Dynamic Angular Form; EmitEvent from Deeper Child to Root (Parent Component)

嗨,我是新手,我正在创建一个 Reactive Form 的项目;基于 RecursiveJSON 文件创建 Dynamic Form 的组件。来源

这是基于 Creating Dynamic Angular Forms with JSON

的 Ionic 改编版

我改编了递归版本程序和其他更改! 我的代码位于 Stackblitz.

我的组件 SelectsComponent 位于 selects.component.ts 文件中,具有选择器 selector: 'selects',我有:

  @Output() addControl = new EventEmitter<JsonFormControls>();

和方法

  public onSelectChange(event: MatSelectChange) {
    console.log(this.form.value);
    console.log('parent:' + this.parentControl || 'root');
    this.control.value = event + '';
    if (this.control.children) {
      this.recursiveConcealer(this.control.children);
      const child = this.control.children.find(
        (child) => child.value === event + ''
      );
      this.newControl(child);
      if (child.siblings) {
        for (let sibling of child.siblings) {
          this.newControl(sibling);
        }
      }
      //Emit Event to Root
      this.addControl.emit(child);
    }
  }

当调用onSelectChange方法时,则执行emit this.addControl.emit(child);

templateselects.component.html文件中,我有这样的代码:

  <ng-container *ngFor="let child of control?.children">
    <div fxFlex="100%">
      <selects
        *ngIf="child.type === 'select'"
        [control]="child"
        [parentControl]="control"
        [formBuilder]="formBuilder"
      ></selects>
    </div>
  </ng-container>

我的 JsonFormComponent 位于 json-form.component.ts 文件中,其中这个方法:

  public onAddControl(addControlEvent: JsonFormControls) {
    this.addControl(addControlEvent);
    addControlEvent.visible = true;
  }

templatejson-form.component.html文件中,代码如下:

<selects
  *ngIf="control.type === 'select'"
  [control]="control"
  [visible]="true"
  (addControl)="onAddControl($event)"
  [formBuilder]="myFormBuilder"
></selects>

当某些 Child-component (SelectsComponent) 不是 Root Parent-Component (JsonFormComponent) 的直子时出现问题,可能是孙子或同级关系, 如:

(0级)JsonFormComponent -> (1级)SelectsComponent -> (2级)SelectsComponent -> (3级)SelectsComponent

如何re-emit从SelectsComponentchild到SelectsComponentparent.

问题:

  1. 如何从(级别 3)SelectsComponent 发送或发出事件到(级别 0)JsonFormComponent
  2. 如何将一些确认事件从(级别 0)JsonFormComponent 发送到(级别 3)SelectsComponent

提前致谢!

我很欣赏不是基于 services 的答案,我知道这可能是一个替代方案。

编辑:

预期的 Console.log(...) 是多少?

console.log(`parent: ${this.parentControl?this.parentControl.name:'root'} -> control.name: ${this.control.name} -> Emitter: ${e?.name}` );

第一个(或根)组件是 company

类似于:

parent: root -> control.name: company -> {Here the last node child}.

根据上图点击

第一次点击(第一级):

parent: root -> control.name: company -> Emitter: Petitioner (C2 -> P2).

第二次点击(二级):

parent: root -> control.name: company -> Emitter: Service (C2 -> P2 -> S2).

示例:第 3 次点击(第三级):

parent: root -> control.name: company -> Emitter: Request (C2 -> P2 -> S2 -> R2).

console.log(或未来的操作)只会在根(即company)的上下文中执行。

你的问题有答案(我希望);

  1. 可以给自己注入SelectsComponent:

    @Optional() @SkipSelf() private selectsComponent: SelectsComponent

然后订阅自己的 addControl EE 并将他的值推送到注入的实例:

ngOnInit(): void {
    if (this.selectsComponent) {
      this.addControl
        .subscribe(e => {
          this.selectsComponent.addControl.next(e);
        });
    }

    this.form = this.rootFormGroup.form;
  }

在这种情况下,您正在同步所有嵌套的 EE;

  1. 对于你的第二个问题,我认为解决方案是将 data/subject 传递到每个 SelectComponent 的 Input 装饰器中(绑定到 children 选择你进入主机组件的输入数据)。

我已经准备了一个示例来说明您的第一个问题是如何工作的,请检查 SelectsComponent。看到每个子组件触发他的父 addControl:Stackblitz

这是 https://stackblitz.com/edit/angular-ivy-6kccps

中的更新解决方案

1.How 从(级别 3)SelectsComponent 向(级别 0)JsonFormComponent 发送或发出事件?

监听 selects.component.html

子组件 selects 发出的 addControl 事件
  <selects
    *ngIf="child.type === 'select'"
    [control]="child"
    [parentControl]="control"
    [formBuilder]="formBuilder"
    (addControl)="handleAddControl($event)"
  ></selects>

发出事件

handleAddControl(data: any) {
    this.addControl.emit(data);
  }

这将从 SelectsComponent 的每个实例发送事件,以冒泡到顶部 JsonFormComponent

2.How 从(级别 0)JsonFormComponent 向(级别 3)SelectsComponent 发送一些确认事件?

我不太确定发送确认需要什么。但是,我假设在原始实例中收到确认后您将执行某些操作,例如更新一些 属性。可以通过向事件有效负载添加回调来实现,如下所示: selects.component.ts

 //Emit Event to Root
public onSelectChange(event: MatSelectChange) {
...
...
...
 const data = {child,
  callback: () => {
    console.log('Executing callback for control with label', this.control.name)
  }
}   

this.addControl.emit(data);

执行json-form中的回调。component.ts

  public onAddControl(addControlEvent: any) {
    if (addControlEvent.callback) {
      addControlEvent.callback();
    }
    this.addControl(addControlEvent);
    addControlEvent.visible = true;
  }