简体   繁体   中英

Angular 2 reactive forms issue

I have a question regarding Angular 2 reactive forms. I'm trying to do two things in my reactive form view:

  1. Have a default value in the dropdown of country name.

  2. Change the country code input field based on the selection of the country name field. See html below is.

country.ts

export class Country {
  countryName: string;
  countryCode: number
}

in-memory-data.service.ts which is my database

import { InMemoryDbService } from 'angular-in-memory-web-api';
import { Injectable }    from '@angular/core';

@Injectable()
export class InMemoryDataService implements InMemoryDbService {`

   createDb() {
    let countries = [
      {
          countryName: 'Saudi Arabia',
          countryCode: '+966'
      }, {
          countryName: 'Bahrain',
          countryCode: '+973'
      }, {
          countryName: 'United Kingdom',
          countryCode: '+44'
      },{
          countryName: 'United Arab Emirates',
          countryCode: '+967'
      },{
          countryName: 'Brazil',
          countryCode: '+55'
      },{
          countryName: 'Czech Republic',
          countryCode: '+420'
      }
    ];
    return {countries};
  }
}

html

<div class="container">

<div class="row">
    <h1 id="header-1"> {{title}}</h1>
    <div id="instructions">
        <p>line 1 for description</p>
        <p>line 2 for description</p>

    </div>
</div>

<form class=" form form-inline" [formGroup]="userForm" novalidate>
    <div class="row from-inline" formArrayName="users">
        <div *ngFor="let user of userForm.controls.users.controls; let i=index">
            <div class="heading">
                <span>{{i + 1}}.{{name}} </span>
                <span class="glyphicon glyphicon-remove pull-right" *ngIf="userForm.controls.users.controls.length > 1"
                   (click)="removeDependent(i)"></span>
            </div>
            <div class="body" [formGroupName]="i">
                <div class="row row-form-fields">
                    <div class="form-group col-xs-12 col-sm-6 col-lg-4">
                        <label class="sr-only" for="countryName">Country name</label>
                        <select class="form-control" id="countryName" formControlName="countryName" >
                            <option *ngFor="let country of countries" [ngValue]="country" >{{country.countryName}}</option>
                        </select>
                        <input type="text" class="form-control" formControlName="countryCode" id="countryCode"/>
                        <div [hidden]="userForm.controls.users.controls[i].controls.countryName.valid ||
                                  (userForm.controls.users.controls[i].controls.countryName.pristine && !submitted)" class="error-alert">
                       country is required
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </div>
    <legend/>
    <div class="form-group">
        <div class="row user-form-btns">
            <div class="col-1-3">
                <template ngbModalContainer/>
                <dependent-modal-component/>
            </div>
            <div class="col-1-3">
                <button class="btn btn-form" (click)="addDependentForm()">add dependents</button>
            </div>
            <div class="col-1-3">
                <button type="submit" class="btn btn-form" id="btn-submit-form" (click)="onSubmit(userForm.value, userForm.valid)"
                    [disabled]="!userForm.valid">Submit</button>
            </div>

        </div>
    </div>
</form>
<div class="row">
    <pre>Is myForm valid?: <br>{{userForm.valid | json}}</pre>
        <pre>form value: <br>{{userForm.value | json}}</pre>
</div>

If you want to set a default value for a control you can do it when you build the form:

FormBuilder

constructor(dataService: InMemoryDataService, private fb: FormBuilder) {
    this.name = 'Angular2';
    this.countries = dataService.createDb().countries;
    this.userForm = new FormGroup({
                       users: new FormArray([])
                    });

    let fg1 = new FormGroup({
      countryName: new FormControl(this.countries[0].countryName),
      countryCode: new FormControl(this.countries[0].countryCode)
    });

Then we will subscribe to the changes on the countryName control to update the countryCode:

    fg1.controls.countryName.valueChanges.subscribe((countryName) => {
        fg1.controls.countryCode.setValue(this.findCountryCodeByCountryName(countryName));
    });
}

Adding a new user:

addDependent() {
    let newGroup = new FormGroup({
          countryName: new FormControl(this.countries[0].countryName),
          countryCode: new FormControl(this.countries[0].countryCode)
        });

    newGroup.controls.countryName.valueChanges.subscribe((countryName) => {
      newGroup.controls.countryCode.setValue(this.findCountryCodeByCountryName(countryName));
    });

    this.userForm.controls.users.push(newGroup);
  }

The HTML bindings will follow on a per group basis:

<div class="body" [formGroupName]="i">
             <div class="row row-form-fields">
               <div class="form-group col-xs-12 col-sm-6 col-lg-4">
                 <label class="sr-only" for="countryName">Country name</label>
                 <select class="form-control" id="countryName" formControlName="countryName">
                   <option *ngFor="let country of countries" [ngValue]="country.countryName">{{country.countryName}}</option>
                 </select>
                 <input type="text" class="form-control" formControlName="countryCode" id="countryCode"/>
                 <div [hidden]="userForm.controls.users.controls[i].valid ||
                                (userForm.controls.users.controls[i].pristine && !submitted)" class="error-alert">
                     country is required
                     </div>
                 </div>
               </div>
            </div>

Using the countryName binding instead of binding the entry country selected adds some overhead where we have to do a lookup every time the value changes instead of just piggybacking off of what we already have stored, but that's what you wanted.

Here's a plunker: http://plnkr.co/edit/T7QcTcPKB1g7h0GbKYSu?p=preview

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM