Angular6 如何将嵌套表单的有效性集成到主表单中

Angular6 如何将嵌套表单的有效性集成到主表单中,angular6,Angular6,我有一个组件a,看起来像这样 总之,用户可以创建不同的部分/答案并保存它们。将为每个保存的答案创建一个矩形按钮。在内部,所有这些都保存在表单中并经过验证。我使用的是ace编辑器,它已经提供了将编辑器用作表单控件的功能 A.ts中的代码片段 createForm() { this.codeEditorForm = this.fb.group({ answer: [null, [this.validateThereIsAtleastOneSavedAnswer(this.a

我有一个组件
a
,看起来像这样

总之,用户可以创建不同的部分/答案并保存它们。将为每个保存的答案创建一个矩形按钮。在内部,所有这些都保存在表单中并经过验证。我使用的是
ace编辑器
,它已经提供了将编辑器用作表单控件的功能

A.ts中的代码片段

  createForm() {
    this.codeEditorForm = this.fb.group({
      answer: [null, [this.validateThereIsAtleastOneSavedAnswer(this.answers),this.validateThereIsNoUnsavedAnswer(this.answers)]],
    });
  }
来自A.html的代码片段

<ace-editor id="editor" class="form-control" formControlName="answer" [ngClass]="validateField('answer')" [(text)]="text"></ace-editor>
我希望只有当
bform
aForm
的验证都通过时,才提交
bform


按照角度设计原理,正确的方法是什么?

正确的方法似乎是
A
实现
ControlValueAccessor
接口

export class A implements OnInit, AfterViewInit,  ControlValueAccessor {
...

...
}
“有负责文本
输入的
DefaultValueAccessor
文本区域的
SelectControlValueAccessor
,处理
select
输入的
SelectControlValueAccessor
,或者处理
复选框的
controlvalueaccessor
,等等。因此,对于这些UI元素,我们不需要创建值访问器,但对于自定义组件,我们需要创建自定义访问器“-

解释-我要求
formB
获取
A
的值,并将其映射到
formB
field5
。但是
Angular
不知道
A
的值是什么。对于
input
字段,
Angular
已经知道文本框的值是映射到A的值但是对于自定义组件,我们必须明确告诉
Angular
自定义组件生成的映射到
表单
字段的值是多少。这是通过实现
ControlValueAccess
接口来实现的

该接口有3个重要方法。 1)
writeValue
这是一种告诉用户界面在模型更改时如何更改的方法。假设自定义组件的用户界面是一个滑块,左端表示0%,右端表示100%。如果模型更改为10/100,则用户界面需要滑动到10%。更新此方法以更改用户界面。在我的情况下,我不需要在中执行任何操作这是因为在我的例子中,数据输入方向是UI到模型,而不是模型到UI(我的模型不创建需要在文本区域中填充的文本)

writeValue(value:any){
    console.log('write value called with value ',value);
  }
2)
registerOnChange
-这与
writeValue
相反。每当UI更改时,模型也需要更改。在我的情况下,每当用户在文本框中写入时,我都要更新模型。”Angular为您提供了一个函数,并要求您在组件中有新值更改时调用该函数,以便它可以更新控件。“-

在我的例子中,我想传播更改,然后单击
A
的保存按钮(
onSaveAnswer
),此时我想传播所有保存的答案的值

answers:Array<AnswerInformation>;
propagateChange = (_: any) => {};

  registerOnChange(fn) {
    console.log('registerOnchange called');
    this.propagateChange = fn;
  }

  inSaveAnswer(){
...
    this.propagateChange(this.answers);
  }
field5
将包含成比例的值(此.answers)。其结构将是
Array;
field5:Array;

我可以添加一个额外的验证来验证
field5
不是像这样的空数组

field5: [null, this.validateField5IsProvided]

  validateField5IsProvided(control:AbstractControl) {

      const f5:Array<AnswerInformation> = control.value;
      if(f5){
        if(f5.length !== 0){
          // console.log('answer field is valid');
          return null;
        } else {
          return {
            validateAnswerIsSaved: { // check the class ShowErrorsComponent to see how validatePassword is used.
              valid: false,
              message: 'The field can\'t be empty. Please make sure to save the field'
            }
          };
        }
      } else {
        return {
          validateAnswerIsSaved: { 
            valid: false,
            message: 'The fieldcan\'t be empty. Please make sure to save the field'
          }
        };
      }
    }
<A #a [readonlyFormStatus]="readonlyFormStatus" (answerSectionsEmitter)="handleAEvent($event)" class="form-control" formControlName="field5" [ngClass]="validateField('field5')" ></A>
field5: [null, this.validateField5IsProvided]

  validateField5IsProvided(control:AbstractControl) {

      const f5:Array<AnswerInformation> = control.value;
      if(f5){
        if(f5.length !== 0){
          // console.log('answer field is valid');
          return null;
        } else {
          return {
            validateAnswerIsSaved: { // check the class ShowErrorsComponent to see how validatePassword is used.
              valid: false,
              message: 'The field can\'t be empty. Please make sure to save the field'
            }
          };
        }
      } else {
        return {
          validateAnswerIsSaved: { 
            valid: false,
            message: 'The fieldcan\'t be empty. Please make sure to save the field'
          }
        };
      }
    }
registerOnTouched() {
    console.log('registerOnTouched called');
  }

  setDisabledState(isDisabled: boolean): void {
    console.log('set disabled called with value ',isDisabled);
    this.editor.setReadOnly(isDisabled);
  }