我有一个组件,它根据给定的对象显示一些表单字段。通常,组件由父组件在循环中调用,每次提供一个新对象,然后子组件根据类型显示正确的元素。
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
),但无论如何它都不起作用:
作为最后一个示例,这是表单的屏幕截图(注意每个可重复输入上方的索引):
最佳答案
我认为 [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/