0
votes

I'm new to Angular2 (or 4?), working my way through the fundamentals..
In the Forms/Reactive Forms - an array of addresses are added with no problem.

However trying to add validators to the address sub-elements doesn't work:
Here's my form building:

constructor(
    private fb: FormBuilder
    ){
    this.createForm();
    }

createForm() {
    this.heroForm = this.fb.group({
        name: ['', [Validators.required, Validators.minLength(6)]],
        secretLairs: this.fb.array([
            this.fb.group({
                street: ['', [Validators.required, Validators.minLength(6)]],
                city:   [''],
                state:  ['', Validators.required],
                zip:    ['']
            })
        ]),
        power: ['',Validators.required],
        sidekick: ''
    });
}

get secretLairs(): FormArray {
    return this.heroForm.get('secretLairs') as FormArray;
}

And (part of) my template:

<div formArrayName="secretLairs" class="well well-lg">
    <b class=header>Secret Lairs</b>
    <div *ngFor="let address of secretLairs.controls; let i=index" [formGroupName]="i" >

{{ showMe(i, address.controls.street) }}

        <h4>Address #{{i + 1}}</h4>
        <div style="margin-left: 1em;">
            <div class="form-group">

                <label class="center-block">Street:</label>
                <input class="form-control" trim formControlName="street">

                <label class="center-block">City:</label>
                <input class="form-control" formControlName="city">

                <label class="center-block">State:</label>
                <select class="form-control" formControlName="state">
                    <option *ngFor="let state of states" [value]="state">{{state}}</option>
                </select>

                <label class="center-block">Zip Code:</label>
                <input class="form-control" formControlName="zip">

            </div>
        </div>
        <br>
    </div>
    <button (click)="addLair()" type="button">Add a Secret Lair</button>
</div>

The ShowMe function: console.logs the street-formControl
- which shows null in both validator and asyncValidator..?
And indeed no (in)validation takes place for the address-elements
- the other validators (and everything else) works perfectly.

What am I missing ?

1
Can you try with Validator.compose on your street items. Validators.compose([]) and new FormControl: street: new FormControl('', Validators.compose(Validators.required, Validators.minLength(6))) etc. - EldarGranulo
Nope => street: new FormControl('', Validators.required) => Makes no difference: validator:null - and an empty street-field is still ng-valid. Also tried the compose( double ) - no validator..? - T4NK3R
All works fine plnkr.co/edit/RpcfJZSZToF5UWoKzdLh?p=preview Try typing in Street field - yurzui
@yurzui - Yep. My problem was: When getting the data (ngOnChanges), I replaced the formArray with a new one where the controls contained only the values - no validators : ( "auto-created" with addresses.map(address => this.fb.group(address)) - T4NK3R

1 Answers

1
votes

Got it - I was overwriting the formArray when new data arrived (ngOnChanges):

setAddresses(addresses: Address[]) {
  const addressFGs = addresses.map(address => this.fb.group(address));
  const addressFormArray = this.fb.array(addressFGs);
  this.heroForm.setControl('secretLairs', addressFormArray);
}

this.fb.group(address) created 4 new formControls with only (default) values - no validators.

Alternative:

createForm() {
    this.heroForm = this.fb.group({
        name:       ['', [Validators.required, Validators.minLength(6)]],
        secretLairs: this.fb.array([]),                         // no controls yet
        power:      ['',Validators.required],
        sidekick:    ''
    });
}

setAddresses(addresses: Address[]) {
    this.heroForm.setControl('secretLairs', new FormArray([])); // rough reset!
    addresses.map( address => this.addLair(address));
}

addLair(adr) {
    this.secretLairs.push(this.fb.group({
        street: [(adr)?adr.street:'', [Validators.required, Validators.minLength(4)] ],
        city:    (adr)?adr.city  :'',
        state:  [(adr)?adr.state :'', Validators.required],
        zip:     (adr)?adr.zip   :''
        }
    ));
}

get secretLairs(): FormArray {
    return this.heroForm.get('secretLairs') as FormArray;
}

The addLair() is also used by a button to append a new address (no adr parameter)
- So I can keep the address-form-building in one place : )