Angular 反应式表单控件值只是用户键入的内容?

Angular reactive form control value(s) are only what the user types?

我有一个反应形式,我正在尝试获取值并将其分配给接口中定义的类型的变量。虽然,此表单是使用 Google Places API 填充的(因此所有表单控件都被禁用且用户无法编辑,除了第一个表单控件 - 该控件是其中的字段用户输入初始地址)。

反应式如下:

ngOnInit() {
    // Initialization of branch Address reactive form (Form 2 - Step 2)
    this.addBranchAddressReactiveForm();
  }

// Form Group 2 - Branch Address (Step 2)
  addBranchAddressReactiveForm() {
    this.addBranchAddressForm = this.fb.group({
      // Branch Address Control
      branchAddress: ['',
        Validators.compose([Validators.required])
      ],
      // Branch Street Name Control
      branchStreetName: [{value: '', disabled: true},
        Validators.compose([Validators.required])
      ],
      // Branch Suburb Control
      branchSuburb: [{value: '', disabled: true},
        Validators.compose([Validators.required])
      ] ,
      // Branch City Control
      branchCity: [{value: '', disabled: true},
        Validators.compose([Validators.required])
      ],
      // Branch Province Control
      branchProvince: [{value: '', disabled: true},
        Validators.compose([Validators.required])
      ],
      // Branch Country Control
      branchCountry: [{value: '', disabled: true},
        Validators.compose([Validators.required])
      ],
      // Branch ZIP Control
      branchZip: [{value: '', disabled: true},
        Validators.compose([Validators.required])
      ]
    });
  }

如上所示,除第一个 (branchAddress) 之外的所有控件都被禁用 - 因为这些控件是在选择地址时填充的。查看 component.html 文件中的表单本身时,您可以看到“值”是动态分配的(因为这些值会根据所选地址而变化):

<form [formGroup]="addBranchAddressForm">
            <ng-template matStepLabel>Enter New Branch Address</ng-template>
            <div class="new-branch-form-container">

              <!-- Main Branch Address Parameter (Input that generates the autocomplete dropdown list) -->
              <mat-form-field>
                <mat-label>Enter New Branch Address</mat-label>
                <input matInput placeholder="Enter a location" formControlName="branchAddress" ngx-google-places-autocomplete #placesRef="ngx-places" [options]="addressOptions" (onAddressChange)="handleAddressChange($event)"/>
                <mat-hint>Enter the address of the new branch and select the appropriate address item</mat-hint>
                <mat-error>Please enter the new branch’s address</mat-error>
              </mat-form-field>

              <!-- Branch Street Name (Autofilled) -->
              <mat-form-field>
                <mat-label>Street Name</mat-label>
                <input matInput formControlName="branchStreetName" readonly value={{streetName}}>
                <mat-hint>The street name of the address selected</mat-hint>
                <mat-error>Please enter the street name of the address specified</mat-error>
              </mat-form-field>
              <br>

              <!-- Branch Suburb (Autofilled) -->
              <mat-form-field>
                <mat-label>Suburb</mat-label>
                <input matInput formControlName="branchSuburb" readonly value={{suburb}}>
                <mat-hint>The suburb of the address selected</mat-hint>
                <mat-error>Please enter a valid suburb</mat-error>
              </mat-form-field>
              <br>

              <!-- Branch City (Autofilled) -->
              <mat-form-field>
                <mat-label>City / Town</mat-label>
                <input matInput formControlName="branchCity" readonly value={{city}}>
                <mat-hint>The city of the address selected</mat-hint>
                <mat-error>Please enter a valid city</mat-error>
              </mat-form-field>

              <!-- Branch Province (Autofilled) -->
              <mat-form-field>
                <mat-label>Province</mat-label>
                <input matInput formControlName="branchProvince" readonly value="{{province}}">
                <mat-hint>The province of the address selected</mat-hint>
                <mat-error>Please enter the province of the address specified</mat-error>
              </mat-form-field>
              <br>

              <!-- Branch Country (Autofilled) -->
              <mat-form-field>
                <mat-label>Country</mat-label>
                <input matInput formControlName="branchCountry" readonly value={{country}}>
                <mat-hint>The country of the address selected</mat-hint>
                <mat-error>Please enter the country of the address specified</mat-error>
              </mat-form-field>
              <br>

              <!-- Branch ZIP (Autofilled) -->
              <mat-form-field>
                <mat-label>ZIP</mat-label>
                <input matInput formControlName="branchZip" readonly value={{zip}}>
                <mat-hint>The ZIP / Postal code of the address selected</mat-hint>
                <mat-error>Please enter the ZIP / Postal code of the address specified</mat-error>
              </mat-form-field>
              <br>
            </div>

            <!-- Button to navigate to previous step in stepper -->
            <button mat-stroked-button matStepperPrevious color="primary">Back</button>

            <!-- Button to navigate to next step in stepper (disabled until branch address form is valid) -->
            <button mat-stroked-button matStepperNext color="primary" [disabled]="!addBranchAddressForm.valid">Next</button>
          </form>

我的问题如下。我希望能够将此表单中的值分配给一个对象,以便我可以通过链接到 Web API(不重要)在数据库中创建记录 - 尽管在尝试分配值时这种形式传递给变量,传递的唯一“值”是用户输入的值 him/herself。因此,例如,如下所示,用户在选择地址之前输入“12”。

这个“12”将是下面代码捕获的唯一值(尽管在地址选择后填充了其余控件):

const branch: Branch = this.addBranchDetailsForm.value;

因此,当记录上述 'branch' 时,输出如下,而不是在每个单独的表单控件中找到的所有值的对象:

我正在按如下方式填充表单控件值:

public handleAddressChange(address: any) {

    // Full unformatted address (Not Displayed)
    this.address = address.formatted_address;
    console.log(this.address);

    // Place id (Not Displayed)
    this.placeId = address.place_id;
    console.log(this.placeId);

    // Latitude coordinate (Not Displayed)
    this.latitude = address.geometry.location.lat();
    console.log(this.latitude);

    // Longitude coordinate (Not Displayed)
    this.longitude = address.geometry.location.lng();
    console.log(this.longitude);

    // Reset street address on method refresh
    this.streetName = "";

    // Street number (Displayed i.t.o)
    for (var i = 0; i < address.address_components.length; i++) {
      for (var x = 0; x < address.address_components[i].types.length; x++) {
        if (address.address_components[i].types[x] === "street_number") {
          this.streetName = JSON.parse(JSON.stringify(address.address_components[i].long_name)) + " ";
        }
      }
    }

    // Street name (Displayed i.t.o)
    for (var i = 0; i < address.address_components.length; i++) {
      for (var x = 0; x < address.address_components[i].types.length; x++) {
        if (address.address_components[i].types[x] === "route") {
          this.streetName += JSON.parse(JSON.stringify(address.address_components[i].long_name));
        }
      }
    }

    // Reset suburb on method refresh
    this.suburb = "";

    // Suburb (Displayed)
    for (var i = 0; i < address.address_components.length; i++) {
      for (var x = 0; x < address.address_components[i].types.length; x++) {
        if (address.address_components[i].types[x] === "sublocality") {
          this.suburb = JSON.parse(JSON.stringify(address.address_components[i].long_name))
        }
      }
    }

    // Reset city on method refresh
    this.city = "";

    // City (Displayed)
    for (var i = 0; i < address.address_components.length; i++) {
      for (var x = 0; x < address.address_components[i].types.length; x++) {
        if (address.address_components[i].types[x] === "locality") {
          this.city = JSON.parse(JSON.stringify(address.address_components[i].long_name))
        }
      }
    }

    // Reset province on method refresh
    this.province = "";

    // Province (Displayed)
    for (var i = 0; i < address.address_components.length; i++) {
      for (var x = 0; x < address.address_components[i].types.length; x++) {
        if (address.address_components[i].types[x] == "administrative_area_level_1") {
          this.province = JSON.parse(JSON.stringify(address.address_components[i].long_name))
        }
      }
    }

    // Reset country on method refresh
    this.country = "";

    // Country (Displayed)
    for (var i = 0; i < address.address_components.length; i++) {
      for (var x = 0; x < address.address_components[i].types.length; x++) {
        if (address.address_components[i].types[x] == "country") {
          this.country = JSON.parse(JSON.stringify(address.address_components[i].long_name))
        }
      }
    }

    // Reset zip on method refresh
    this.zip = "";

    // ZIP (Displayed)
    for (var i = 0; i < address.address_components.length; i++) {
      for (var x = 0; x < address.address_components[i].types.length; x++) {
        if (address.address_components[i].types[x] == "postal_code") {
          this.zip = JSON.parse(JSON.stringify(address.address_components[i].long_name))
        }
      }
    }
  }

handleAddressChange 方法接受在表单的第一个控件(字段)中输入的地址,如下所示:

<!-- Main Branch Address Parameter (Input that generates the autocomplete dropdown list) -->
              <mat-form-field>
                <mat-label>Enter New Branch Address</mat-label>
                <input matInput placeholder="Enter a location" formControlName="branchAddress" ngx-google-places-autocomplete #placesRef="ngx-places" [options]="addressOptions" (onAddressChange)="handleAddressChange($event)"/>
                <mat-hint>Enter the address of the new branch and select the appropriate address item</mat-hint>
                <mat-error>Please enter the new branch’s address</mat-error>
              </mat-form-field>

当此方法被激活时,上面看到的变量(例如 this.suburb / this.city)被填充 - 因此这些变量显示为相应输入中的值属性的一部分场地。例如:

<!-- Branch Suburb (Autofilled) -->
              <mat-form-field>
                <mat-label>Suburb</mat-label>
                <input matInput formControlName="branchSuburb" readonly value={{suburb}}>
                <mat-hint>The suburb of the address selected</mat-hint>
                <mat-error>Please enter a valid suburb</mat-error>
              </mat-form-field>
              <br>

在上面你可以看到变量 (this.suburb) 被设置为值属性为 {{suburb}}..

任何可能出现这种情况的原因都值得赞赏。谢谢你的时间。

由于有禁用字段,formGroup.value 没有 return 这些值。您将需要调用 formGroup 的 getRawValue() 方法来获取字段值,而不管它们的 enabled/disable 状态如何。

您需要这样做:

const branch: Branch = this.addBranchDetailsForm.getRawValue();

来自 Angular 文档:https://angular.io/api/forms/FormGroup#getRawValue

getRawValue() - Retrieves all values regardless of disabled status. The value property is the best way to get the value of the group, because it excludes disabled controls in the FormGroup.

从您更新的代码中可以清楚地看出您没有设置 formGroup 值,因此尽管使用 getRawValue() 方法,您得到的是空白值。这里你没有更新 formControl。

 this.streetName = JSON.parse(JSON.stringify(address.address_components[i].long_name)) + " ";

您需要将其更改为:

this. addBranchDetailsForm.get('branchStreetName').setValue(JSON.stringify(address.address_components[i].long_name)) + " ";

同样适用于所有其他字段。