javascript - 在 ng-template 中访问 FormArray 引用

标签 javascript html angular forms

我有一个组件,它根据给定的对象显示一些表单字段。通常,组件由父组件在循环中调用,每次提供一个新对象,然后子组件根据类型显示正确的元素。

Here is the StackBlitz example

但有时,该元素可能是一个可迭代,一个可重复的元素(在FormArray 的情况下)。我有以下代码:

<div [formGroup]="form">

  <ng-template #formTmpl
               let-field="field"
               let-index="index">
    <pre>index: {{ index }}</pre>
    <label [attr.for]="!!question.iterable ? question.key + index : question.key">{{ question.label }}</label>

    <div [ngSwitch]="question.controlType">

      <div [attr.formArrayName]="!!question.iterable ? question.key : null">
        <input *ngSwitchCase="'textbox'"
               [class]="isValid ? config.validClass : config.invalidClass"
               [formControlName]="!!question.iterable ? index : question.key"
               [placeholder]="question.placeholder"
               [id]="!!question.iterable ? question.key + index : question.key"
               [type]="question['type']">

        <select [id]="question.key"
                *ngSwitchCase="'dropdown'"
                [class]="isValid ? config.validClass : config.invalidClass"
                [formControlName]="question.key">
          <option value=""
                  disabled
                  *ngIf="!!question.placeholder"
                  selected>{{ question.placeholder }}</option>
          <option *ngFor="let opt of question['options']"
                  [value]="opt.key">{{ opt.value }}</option>
        </select>

        <textarea *ngSwitchCase="'textarea'"
                  [formControlName]="question.key"
                  [id]="question.key"
                  [class]="isValid ? config.validClass : config.invalidClass"
                  [cols]="question['cols']"
                  [rows]="question['rows']"
                  [maxlength]="question['maxlength']"
                  [minlength]="question['minlength']"
                  [placeholder]="question.placeholder"></textarea>
      </div>
    </div>

    <div class="errorMessage"
         *ngIf="!isValid">{{ question.label }} is required</div>

  </ng-template>

  <div *ngIf="question.iterable; else formTmpl">
    val {{questionArray.value | json}}
    <div *ngFor="let field of questionArray.controls; let i=index; last as isLast">
      <ng-container [ngTemplateOutlet]="formTmpl"
                    [ngTemplateOutletContext]="{field: field, index: i}"></ng-container>
      <button *ngIf="question.iterable && isLast"
              type="button"
              (click)="addItem(question)">+</button>
    </div>
  </div>

</div>

目前,我正在 inputs 上测试元素的可重复性。

所以对于一个元素,它运行良好,但它无法获取对可选指令的引用:[attr.formArrayName]="!!question.iterable ? question.key : null"

如果尝试以下操作(将输入直接放入 ng-container,而不调用 ng-template):

  <div *ngIf="question.iterable; else formTmpl">
    val {{questionArray.value | json}}
    <div *ngFor="let field of questionArray.controls; let i=index; last as isLast">
      <input [class]="isValid ? config.validClass : config.invalidClass"
             [formControlName]="i"
             [placeholder]="question.placeholder"
             [id]="question.key"
             [type]="question['type']">
      <button *ngIf="question.iterable && isLast"
              type="button"
              (click)="addItem(question)">+</button>
    </div>
  </div>

输入框显示的很好,Form的值也很好的绑定(bind)了

奇怪的是 ng-template 中每个字段的 formControlName 都将它们的值很好地绑定(bind)到表单。

我在表单初始化时得到的错误是:

ERROR Error: Cannot find control with unspecified name attribute
    at _throwError (vendor.js:74769)
    at setUpControl (vendor.js:74593)
    at FormGroupDirective.addControl (vendor.js:78338)
    at FormControlName._setUpControl (vendor.js:78989)
    at FormControlName.ngOnChanges (vendor.js:78912)
    at checkAndUpdateDirectiveInline (vendor.js:59547)
    at checkAndUpdateNodeInline (vendor.js:70213)
    at checkAndUpdateNode (vendor.js:70152)
    at debugCheckAndUpdateNode (vendor.js:71174)
    at debugCheckDirectivesFn (vendor.js:71117)

然后,如果我向 formArray 添加一个新元素,新元素出现但未绑定(bind),并且此新错误显示:

ERROR Error: Cannot find control with name: '1'
    at _throwError (vendor.js:74769)
    at setUpControl (vendor.js:74593)
    at FormGroupDirective.addControl (vendor.js:78338)
    at FormControlName._setUpControl (vendor.js:78989)
    at FormControlName.ngOnChanges (vendor.js:78912)
    at checkAndUpdateDirectiveInline (vendor.js:59547)
    at checkAndUpdateNodeInline (vendor.js:70213)
    at checkAndUpdateNode (vendor.js:70152)
    at debugCheckAndUpdateNode (vendor.js:71174)
    at debugCheckDirectivesFn (vendor.js:71117)

那么我怎样才能使字段考虑到 formArrayName 属性呢?

您可以在下面看到属性存在于标记中(但我认为它通常是 ng-reflect-name),但无论如何它都不起作用:

enter image description here

作为最后一个示例,这是表单的屏幕截图(注意每个可重复输入上方的索引):

enter image description here

Here is the StackBlitz example

最佳答案

我认为 [attr.formArrayName]="!!question.iterable ? question.key : null" 绑定(bind)不起作用,因为它是作为 attribute binding instead of input binding 执行的

但是,当我们将其转换为输入绑定(bind)时,您的用例中的非 FormArray 问题会出现新错误。

因此,使用旧的 formControl 指令代替 formControlName 可以解决问题。

[formControl]="form.get(question.iterable ? [question.key, index] : question.key)"

同样,通过这种方法,您不再需要 [attr.formArrayName]="!!question.iterable ? question.key : null" 绑定(bind)

这是一个有效的 demo

关于javascript - 在 ng-template 中访问 FormArray 引用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56738519/

相关文章:

angular - 我如何通过路由在 Angular 中托管文件?

javascript - 如何使用 Firebase Analytics 从 SPA(单页应用程序)网络应用程序发送 page_view 事件?

javascript - 无法循环 JQuery .hover()

javascript - 如何将函数修复到允许下一个函数正确计算的位置?

适用于 Android 平板电脑的 JavaScript、CSS、HTML5 编辑器

angular - RxJS 6 - 取消/结束管道

Angular 子路由重新加载父组件

javascript - 更改多个 iframe 的内容

javascript - 从数组中间获取相等填充的键

javascript - 使用 Javascript 突出显示带有子菜单的当前页面链接