【问题标题】:FormGroup updating FormControl value for radios immediately when they are added添加无线电时,FormGroup 立即更新无线电的 FormControl 值
【发布时间】:2018-11-16 15:30:30
【问题描述】:

问题

FormGroup 添加无线电类型输入时,FormControl 的值会立即更新。此外,更改选定的单选按钮不会更新 FormControl 值。

代码

我的代码是一个动态表单系统,它使用服务 (FormService) 来维护一个单例 FormGroup,并根据需要添加和删除输入。

我的所有输入都扩展了一个名为 InputBaseComponent 的基本输入类,它导入 FormService 并为自己创建一个表单控件,并通过服务将其添加到 FormGroupInputBaseComponent 还包含所有输入都相同的所有通用功能。

FormService

表单服务是一个非常通用的服务,它使用 getter/setter 函数来规范 FormGroup。该服务由InputBaseComponent 导入,每个单独的输入组件都对其进行了扩展。

import { Injectable } from '@angular/core';
import { FormGroup } from '@angular/forms';

@Injectable()
export class FormService {

    // An arry of all the inputs in the form
    inputs: any[] = [];

    // The form group for this instance of the form service singleton
    formGroup: FormGroup = new FormGroup({});

    // Adds an input to the array of inputs in the form
    addInput( input: any ){

        // Push the input to the array if it's not already in the inputs array
        if ( this.inputs.indexOf(input) === -1 ) this.inputs.push(input);

        // Push the input's form control to the form group if it doesn't already exist
        if ( !this.formGroup.contains(input.name) ) this.formGroup.addControl(input.name, input.formControl);
    }

    // Removes an input from the array of inputs in the form
    removeInput( input: any ){

        // Remove the input from the array if it exists
        this.inputs.filter( arrayInput => arrayInput !== input);

        // Remove the control from the form group
        if ( this.formGroup.contains(input.name) ) this.formGroup.removeControl(input.name);
    }
}

BaseInputComponent

这是所有实际输入组件扩展的基本输入组件。这样做是为了将所有通用功能保存在一个地方,以免为每个输入重复代码。为了简单起见,我在最后截断了所有输入,但相信我,它们就在那里。

// ---------- Imports ---------- //

    import { Component, OnInit, Input, Output, EventEmitter } from '@angular/core';
    import { FormControl, Validators, ValidatorFn } from "@angular/forms";

    /// ---------- Dependencies ---------- ///

        import { FormService } from "../form.service";

// ---------- Components ------- //
    @Component({
        selector: 'input-base-component-do-not-use-directly',
        template: ``
    })
    export class InputBaseComponent implements OnInit {

        /// ---------- Constructor ---------- ///

            constructor ( public formService: FormService ){};

        /// ---------- Properties ----------- ///

            // A reference to this form input's form control
            formControl: any;

        /// ---------- Methods -------------- ///

            // On init set up the form control with the proper validators
            ngOnInit() {

                // Setup the form control with the proper validators
                this.setupFormControl( this.getValidators() );
            }

            // Creates an array of all of the validator functions that should apply to the input and returns it
            getValidators(): ValidatorFn[] {

                // Create the validators array
                let validators: any[] = [];

                // Set the max length validator
                if (this.maxLength) validators.push(Validators.maxLength(this.maxLength));

                // Set the min length validator
                if ( this.minLength ) validators.push(Validators.minLength(this.minLength));

                // Set the required validator
                if ( this.required ) validators.push(Validators.required);

                // Include any custom validators
                if ( this.customValidators && this.customValidators.length ) validators = validators.concat(this.customValidators);

                // Return the array of validator functions
                return validators;
            }

            // Sets up the form control and adds it to the form service
            setupFormControl( validators: ValidatorFn[] ): void {

                // Create the form control for this input
                if (this.formService.formGroup.contains(this.name)) {
                    this.formControl = this.formService.formGroup.get(this.name)
                } else {
                    this.formControl = this.getNewFormControl( validators );
                    this.formService.addInput(this);
                }

                // Update the parent component whenever this input's value is changed
                this.formControl.valueChanges.subscribe( newValue => this.valueChange.emit(newValue));

                // Add the input to the form group
                this.formService.addInput(this);
            }

            // Takes an array of validator functions and returns a new form control with all of the proper setup for this input
            getNewFormControl( validators: ValidatorFn[] ): FormControl {

                // Return a new form control for this form
                return new FormControl( this.value || null, { validators: validators, updateOn: this.validateOn } );
            }
    }

兴趣代码

如果您查看setupFormControl 函数的以下行,您可以看到我们正在检查FormGroup 以查看是否已经存在具有为输入指定名称的FormControl,例如单选按钮和复选框。如果它已经存在,它将使用现有的FormControl 作为输入的表单控件。这样做是为了模仿正确的标记,以便在反应式表单中使用单选按钮和复选框,其中组中的每个单选按钮或复选框都使用相同的表单控件。

// Create the form control for this input
if (this.formService.formGroup.contains(this.name)) {
    this.formControl = this.formService.formGroup.get(this.name)
} else {
    this.formControl = this.getNewFormControl( validators );
    this.formService.addInput(this);
}

实现此代码的标记如下:

<!-- input -->
<input 
    #input 
    [formControl]="formControl" 
    [type]="type" 
    [name]="name" 
    [id]="idStr" 
    [value]="value" 
    tabindex="-1" 
/>

可能的解决方案

如前所述,一旦添加表单控件(或在第一个单选框/复选框之后的控件上重新使用),FormControl 实例的值就会更新为最后添加的单选框或复选框。此外,无论何时更改所选单选或复选框,FormControl 的值都不会更新。

所需的功能

此处所需的功能是FormControl 实例的value 属性将保持为null,直到用户选择单选或复选框。此外,当更改选定的单选或复选框时,FormControl 的值应该更新。

【问题讨论】:

  • 您可以删除 [value]="value" 并分享您看到的具体行为。
  • 该值未按预期更新,但在与单选按钮交互时该值未更新。

标签: angular angular5


【解决方案1】:

所以这里有两个答案,一个是值,另一个是值不更新。

为什么要应用该值

如果你查看函数getNewFormControl,你有这行代码:

// Return a new form control for this form
return new FormControl( this.value || null, { validators: validators, updateOn: this.validateOn } );

需要更新此行以考虑未设置复选框和单选按钮的值,因此使用三元组进行简单检查即可解决问题:

// Return a new form control for this form
return new FormControl( this.type !== "radio" && this.type !== "checkbox" ? this.value || null : null, { validators: validators, updateOn: this.validateOn } );

为什么值没有更新

Angular 2+ 中有一个关于单选和复选框的动态输入类型的已知错误。对于这些输入类型,您不能将动态类型应用于输入。

此代码将正常工作:

<!-- input -->
<input 
    #input 
    [formControl]="formControl" 
    type="radio" 
    [name]="name"
    [value]="value"
/>

这段代码根本不起作用:

<!-- input -->
<input 
    #input 
    [formControl]="formControl" 
    [type]="myInputType" 
    [name]="name"
    [value]="value"
/>

不幸的是,这意味着使用ngIf 和两个需要单独更新的单独输入。这是自 Angular 2 RC.6 以来的一个已知错误,如果他们能修复它会很好。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2021-01-29
    • 1970-01-01
    • 1970-01-01
    • 2015-06-23
    • 1970-01-01
    • 1970-01-01
    • 2010-11-02
    • 1970-01-01
    相关资源
    最近更新 更多