【问题标题】:Angular 8 - FormArray "No value accessor for form control with path"Angular 8 - FormArray“无路径表单控件的值访问器”
【发布时间】:2021-02-28 18:54:35
【问题描述】:

我在表单上使用ng-select,但现在我想在自定义组件上包装它的特定配置。问题是我正在使用包含其中几个的FormArray,在下一个方式:

this.profileForm = this.formBuilder.group(
  {
    ...
    linkedRoles: this.formBuilder.array([])
  }
);

这个linkedRoles 被下一个FormGroup 填充:

let fgRoles: FormGroup;

for (let i = 0; i < this.userRoles.length; i++) {
  fgRoles = this.formBuilder.group({
    activeRole: [{ value: null }],
    roles: [{ value: null }]
  });
  this.linkedRoles.push(fgRoles);
  this.linkedRoles.controls[i].setValue({
    activeRole: this.userRoles[i].role,
    roles: this.extractUserRoles(this.userRoles[i])
  });

为了简单起见,也创建了一个 getter:

get linkedRoles(): FormArray {
  return <FormArray>this.profileForm.get("linkedRoles");
}

在此之后,在我的模板中,我使用了这个完美的作品:

<form [formGroup]="profileForm">
  ...

  <table>
    ...
    <tbody>
      <tr formArrayName="linkedRoles"
        *ngFor="let usuR of userRoles;
          let idx = index"
      >
        ...
        <td data-label="Roles" [formGroupName]="idx">
          <ng-select #rolesNgSelect
            [hideSelected]="false"
            bindLabel="rol"
            ...
            formControlName="roles"
          >

            <ng-template ng-label-tmp let-item="item">
              ...
            </ng-template>

            <ng-template ng-option-tmp let-item="item">
              ...
            </ng-template>

          </ng-select>
        </td>
      </tr>
    </tbody>
  </table>

</form>

现在,我试图用我的自定义组件role-selector 替换ng-select,它基本上从ng-select 接收所有必要的属性并将其包装在模板中。我之前的模板的变化如下:

<tr formArrayName="linkedRoles"
  *ngFor="let usuR of userRoles;
    let idx = index;
    let ctrlRol of linkedRoles.controls"
>
  <td>
    <app-role-selector
      [hideSelected]="false"
      bindLabel="rol"
      ...
      formControlName="roles"
    >
    </app-role-selector>
  </td>
</tr>

有了这个细微的变化,我在控制台中收到了下一个错误:

ERROR Error: No value accessor for form control with path: 'linkedRoles -> 0 -> roles'

最奇怪的是,当我单击出现的无样式框时,它加载并几乎可以正常工作。我应该将我的formControlName 标记移动到组件模板中的ng-select 吗?

可能的解决方案

正在寻找解决方案,I found the interesting ngDefaultControl。将此指令添加到我的自定义组件使其按预期运行。现在看起来像这样:

<app-role-selector
  [hideSelected]="false"
  bindLabel="rol"
  ...
  ngDefaultControl
  formControlName="roles"
>

唯一的反面是我不完全理解为什么这是必要的,如果这是最好的解决方案。

【问题讨论】:

    标签: angular formarray form-control angular-ngselect


    【解决方案1】:

    错误为No value accessor for form control with path: 'linkedRoles -&gt; 0 -&gt; roles'

    要解决这个问题,首先找到名称为roles 的控件。这是ng-select。但是我们知道ng-select 有一个ValueAccessor...那为什么Angular 会抱怨呢?

    原因基本上是你在声明组件的模块中没有导入NgSelectModule

    但为什么 Angular 不抱怨未知元素? 请参阅此链接 Ivy is not complaining about unknown element inside ng-template #36171。 Angular 不会抱怨未知元素,但会抱怨 ValueAccessor

    【讨论】:

    • 欧文,我非常明白你在说什么,但也许我做错了什么。我的roles 控件现在在我的自定义组件app-role-selector 中定义,而不是在我的ng-select 中。出于好奇,在寻找解决方案时,我发现了ngDefaultControl 指令,它看起来像我预期的那样工作。
    • 你能分享你声明组件的模块吗?
    【解决方案2】:

    假设您在app-role-selector 中有ng-select 相关模板。

    Parent.component.html

    // *ngFor="let role of linkedRoles"
    
    <app-role-selector
          [hideSelected]="false"
          bindLabel="rol"
          ...
          [parentFormArray]='role'>
    </app-role-selector>
    

    角色选择器.component.ts

     export class RoleSelector {
    
        @Input() parentForm: FormGroup;
    }
    

    角色选择器.component.html

    <form [formGroup]="parentForm"> // ----> this will have the ref of fgRoles (formGroup) 
         <ng-select #rolesNgSelect
                [hideSelected]="false"
                bindLabel="rol"
                ...
                formControlName="roles"> ----> fgRoles.get('roles')
          ...
         </ng-select>
    </form>
    

    现在让我们理解下面的错误

    ERROR Error: No value accessor for form control with path: 'linkedRoles -> 0 -> roles'
    

    当我们在&lt;app-role-selector&gt; 中添加formControlName 时,这意味着我们告诉 Angular 将&lt;app-role-selector&gt; 视为任何其他输入字段。但是我们必须将组件配置为像输入元素一样工作(即存储值并与表单元素交互)。

    More details about Custom Value Accessor

    【讨论】:

    • 感谢您的回复,拉利特。我现在明白你在做什么,实际上我试图做类似的事情(没有成功)。问题是我的组件是其他领域更大形式的一部分,我正在努力尊重这种结构。在寻找解决方案时,我发现了有趣的 ngDefaultControl 指令,它可以解决问题并使我的组件按预期工作。
    猜你喜欢
    • 2018-12-24
    • 1970-01-01
    • 2020-08-29
    • 2020-08-18
    • 1970-01-01
    • 2021-05-20
    • 2021-09-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多