简体   繁体   English

Angular - 反应式表单:如何正确获取动态和可重用子表单的值

[英]Angular - Reactive Form: How to correctly get values of dynamical and reusable sub-forms

I am working on a form as below我正在制作如下表格

在此处输入图像描述

在此处输入图像描述

My code我的代码

nested-form.component.ts嵌套-form.component.ts

public nestedForm: FormGroup;
constructor(
    private formBuilder: FormBuilder) {
    this.calibrationForm = this.buildFormGroup(formBuilder);

  }

buildFormGroup(formBuilder: FormBuilder): FormGroup {
    return  new FormGroup({
      motor: new FormControl('', Validators.required),
      properties: new FormControl(""),
    });
  }

save() {
    console.log(this.nestedForm.value);
}

nested-form.component.html嵌套形式.component.html

<form [formGroup]="nestedForm" >

    <mat-select class="field-select" [(ngModel)]="_selectedMotor"
                    (selectionChange)="selectMotor($event.value)" formControlName="motor">
                    <mat-option class="select-option" *ngFor="let item of motors" [value]="item">
                        item</b>
                    </mat-option>
                </mat-select>

    <app-properties formControlName="properties" [type] = "_selectedMotor"></app-properties>
   ...
</form>

properties.component.ts属性.component.ts

@Component({
  ...
  providers: [
    {
      provide: NG_VALUE_ACCESSOR,
      useExisting: forwardRef(() => PropertiesComponent),
      multi: true
    },
    {
      provide: NG_VALIDATORS,
      useExisting: forwardRef(() => PropertiesComponent),
      multi: true
    }
  ]
})

export class PropertiesComponent implements OnInit, ControlValueAccessor {
    @Input() type: string = null;
    public propertiesForm: FormGroup;
    ngOnInit(): void {
        this.propertiesForm = this.buildFormGroup(this.formBuilder);
    }

    ngOnChanges(changes): void {
        this.propertiesForm = this.buildFormGroup(this.formBuilder);
    }

    buildFormGroup(formBuilder: FormBuilder): FormGroup {
        switch (this.type) {
          case "OLD":
           
            return new FormGroup(
              {
                tilt: new FormControl(0, [Validators.required]),
                fine_tilt: new FormControl(0, [Validators.required]),
                rotate: new FormControl(0, [Validators.required]),
                fine_rotate: new FormControl(0, [Validators.required])
              });

          case "VINTEN":
           
            return new FormGroup(
              {
                vinten_tilt: new FormControl(0, [Validators.required]),
                vinten_rotate: new FormControl(0, [Validators.required])

              });
        }
     }

  public onTouched: () => void = () => { };
  writeValue(val: any): void {
    val && this.propertiesForm.setValue(val, { emitEvent: false });
  }
  registerOnChange(fn: any): void {
    this.propertiesForm.valueChanges.subscribe(fn);
  }
  registerOnTouched(fn: any): void {
    this.onTouched = fn;
  }
  setDisabledState?(isDisabled: boolean): void {
    isDisabled ? this.propertiesForm.disable() : this.propertiesForm.enable();
  }

  validate(c: AbstractControl): ValidationErrors | null {
    return this.propertiesForm.valid ? null : { invalidForm: { valid: false, message: "propertiesForm fields are invalid" } };
  }
  ...
}

properties.component.html属性.component.html

<form *ngIf="type" class="col" [formGroup]="propertiesForm" [ngSwitch]="type">
    <div *ngSwitchCase="OLD">
        <input type="number" class="field-input" id="rotate" formControlName="rotate" />
        <input type="number" class="field-input" id="fine_rotate" formControlName="fine_rotate" />
        <input type="number" class="field-input" id="tilt" formControlName="tilt" />
        <input type="number" class="field-input" id="fine_tilt" formControlName="fine_tilt" />
    </div>

    <div *ngSwitchCase="VINTEN">
        <input type="number" class="field-input" id="rotate" formControlName="vinten_rotate" />
        <input type="number" class="field-input" id="tilt" formControlName="vinten_tilt" />
    </div>
</form>

Result:结果:

Let's say OLD is a default, when the form is loaded.假设加载表单时,OLD 是默认值。

I entered all fields and click Save button for OLD, the form values is collected correctly as expected.我输入了所有字段并单击 OLD 的保存按钮,表单值按预期正确收集。

However, when I switched from OLD to VINTEN, the form UI is updated but valid/invalid state of Save button is not working any more, and after clicking Save button, the form values are still the OLD properties values, not VINTEN properties values.但是,当我从 OLD 切换到 VINTEN 时,表单 UI 已更新,但保存按钮的有效/无效 state 不再起作用,并且单击保存按钮后,表单值仍然是 OLD 属性值,而不是 VINTEN 属性值。

Did I miss something or make something wrong?我错过了什么或做错了什么吗? Any suggestion is appreciated.任何建议表示赞赏。

To notify parent control about internal changes you have to listen propertiesForm.valueChanges() .要通知父控件内部更改,您必须侦听propertiesForm.valueChanges()

And call fn that you were given by registerOnChange(fn: any): void并调用 registerOnChange( fn registerOnChange(fn: any): void给你的 fn

onModelChange = () => {}


 ngOnInit(): void {
    this.propertiesForm = this.buildFormGroup(this.formBuilder);
    this.propertiesForm.valueChanges().subscribe(value => this.onModelChange(value))
}

registerOnChange(fn: any): void {
  this.onModelChange = fn;
}

Angular forms Angular forms

Thanks Yuriry,谢谢尤里,

Though his answer didn't resolve my issue directly and fully, it's a main lead for me to the final solution of my issue.虽然他的回答并没有直接彻底地解决我的问题,但它是我最终解决问题的主要线索。 Just leave here for any reference:留在这里以供参考:

export class PropertiesComponent implements OnInit, ControlValueAccessor {
    @Input() type: string = null;
    subscriptions: Subscription[] = [];

    ...

    ngOnChanges(changes): void {
       this.subscriptions.forEach(s => s.unsubscribe());
       this.propertiesForm = this.buildFormGroup(this.formBuilder);
       this.subscriptions.push(
           this.propertiesForm.valueChanges.subscribe(value => {
             this.onChange(value);
             this.onTouched();
         })
       );
    }
    
    ...
   onChange: any = () => {};
   registerOnChange(fn: any): void {
     this.onChange = fn;
   }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 如何在 Angular 中实现嵌套到一个父表单组件中的动态反应子表单? - How to implement dynamic reactive sub-forms nested into one Parent Form component in Angular? 具有动态变化的子表单的复杂 Angular 表单 - Complex Angular forms with dynamically changing sub-forms Angular Material Reactive Form 无法正确获取表单值 - Angular Material Reactive Form does not get form values correctly 如何在 Angular 中为反应形式构建可重用字段 - How to build reusable field for reactive form in Angular 从 Angular 中的反应式 Forms 中的表单组中获取数组的值 - Get the values from array from Form Group in Reactive Forms in Angular 如何在Angular中获取反应形式输入的值? - How to get values of reactive form inputs in Angular? Angular:如何正确重置反应形式 - Angular: How to correctly reset reactive forms 如何从 FormArray 获取值 - Angular Reactive Forms - How to get values from FormArray - Angular Reactive Forms Angular Reactive 表单:如何获取刚刚更改的值 - Angular Reactive forms : how to get just changed values 如何在 Angular 8 中正确使用表单数组/动态生成的表单与反应式表单 - How does one correctly use a formarray/dynamic generated form in conjunction with reactive forms in Angular 8
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM