1

I'm trying to create dynamic from groups based on initial data with filled content and add/remove from groups. Unfortunately it is not working.

Expected behavior is,

  • Coutry dropdown would be loaded with data and highlighted with selected value which is working fine already.
  • Selected country states dropdown data should be loaded by default with selected value from initial data stateCode and when changing the country too which is not working currently.
  • While clicking the add button, by default "United states" country and respective states data should be loaded. States dropdown should be selected by default with "--select--".

Note: All data will be coming from API. Testing purpose I have added static objects for Countries and States.

enter image description here

Here my attempt

https://stackblitz.com/edit/angular-8-app-example-fkjzfe-wekubn?file=src%2Fapp%2Fapp.component.ts

Current behaviour demo

https://angular-8-app-example-fkjzfe.stackblitz.io/

HTML

  <form [formGroup]='entityForm'>
              <div formArrayName="optionGroups" class="ui-g ui-g-12 ui-g-nopad " >
                <div  style="width: 100%;
    display: flex; margin-bottom:10px" class="ui-g  ui-g-12 ui-g-nopad " *ngFor="let item of entityForm.controls['optionGroups'].controls; let $index=index" [formGroup]="item">        
                  <div class="ui-md-4">                   
                    <label class="mandatory"
                  >Country
                  <span class="colon"></span>
                </label>
                <select formControlName="country" class="ui-inputtext" (change)="onCountryChange(entityForm.controls['optionGroups'].controls[$index].controls['country'].value, $index)" > 
                  <option>--Select--</option>
                  <option *ngFor="let c of countries" [ngValue]="c.countryCode">{{c.country}}</option>                 
                </select>
              </div>
              <div class="ui-md-4">

                <label class="lbl-hidden"> State </label>
                <select formControlName="state" class="ui-inputtext"> 
                  <option>--Select--</option>
                  <option *ngFor="let state of states[entityForm.controls['optionGroups'].controls[$index].controls['country'].value]" value="state.code">{{state.state}}</option>
              </select>
              </div>
              <div class="ui-md-3">
                <label class="lbl-hidden"> Number </label>
                <input
                  type="text"
                  pInputText
                  class="form-control"
                  formControlName="place"    
                />
                </div>
                <div class="ui-md-1">
                 
                  <button (click)='removeOptionGroup(i)'  style="min-width: auto;"  pButton icon="fa fa-minus">Remove</button>
                </div>
                </div>
              </div>
            </form>        
            <button class="add-remove-btn" pButton (click)='addOptionGroup()' icon="fa fa-plus">Add</button>` 

TS

import { Component, OnInit, ViewChild } from '@angular/core'

import { FormBuilder, Validators, FormArray, FormGroup, FormControl } from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ]
})
export class AppComponent implements OnInit  {
  public countryOptions:any = [];
  public stateOptions:any = [];

  public countries = [];
  public states = [];

  public entityForm: FormGroup;

constructor(private fb: FormBuilder) {
  this.entityForm = this.fb.group({
    optionGroups : this.fb.array([]),
});

this.countries = this.countryOptions
this.states=[];
}


public addOptionGroup(){

  const fa = this.entityForm.controls["optionGroups"] as FormArray;
   //fa.setValue("--Select--");
  fa.push(this.newOptionGroup());


  }

  public removeOptionGroup(index: number){

    const fa = this.entityForm.controls["optionGroups"] as FormArray;
  
    fa.removeAt(index);
  
    }

    onCountryChange(selectedCountry: string , formIndex : number) : void {
      this.states[selectedCountry] = this.getStates(selectedCountry)
    }

    private newOptionGroup() {
      return new FormGroup({          
          country: new FormControl("--select--"),
          state: new FormControl("--select--"),
          place: new FormControl("GGG"),

      });
  }


  getStates(selectedCountry) {
    //API call

    switch(selectedCountry) {
      case "US" : 
        this.stateOptions =[
      {id: 14, state: "Alabama", code: "AL", countryCode: "US"},
      {id: 15, state: "Alaska", code: "AK", countryCode: "US"},
      {id: 17, state: "Arizona", code: "AZ", countryCode: "US"},
      {id: 18, state: "Arkansas", code: "AR", countryCode: "US"},
      {id: 19, state: "California", code: "CA", countryCode: "US"}
      ]
      break;

     case  "CA" :
       this.stateOptions =[{id: 37, state: "Marshall Islands", code: "MH", countryCode: "CA"},
      {id: 4, state: "New Brunswick", code: "NB", countryCode: "CA"},
      {id: 5, state: "Newfoundland and Labrador", code: "NL", countryCode: "CA"},
      {id: 53, state: "Northern Mariana Islands", code: "MP", countryCode: "CA"},
      {id: 6, state: "Northwest Territories", code: "NT", countryCode: "CA"}]
      break;    
    default: 
     this.stateOptions =[
      {id: 14, state: "Alabama", code: "AL", countryCode: "US"},
      {id: 15, state: "Alaska", code: "AK", countryCode: "US"},
      {id: 17, state: "Arizona", code: "AZ", countryCode: "US"},
      {id: 18, state: "Arkansas", code: "AR", countryCode: "US"},
      {id: 19, state: "California", code: "CA", countryCode: "US"}
      ]
      break;
  }
    return this.stateOptions;

   }

   initFormArray(initForm:any) {
    const formArray = this.entityForm.get('optionGroups') as FormArray;
    initForm.map((item, index) => {
      formArray.push(this.createForms(item, index));
    });
    this.entityForm.setControl('optionGroups', formArray);
   }

   createForms(adresse, index): FormGroup {
   
    let formGroup: FormGroup = new FormGroup(
      {
        country: new FormControl(adresse.countryCode),
        state: new FormControl(adresse.stateCode),
        place: new FormControl(adresse.fileNumber)
      }
    );
 this.onCountryChange(adresse.select1, index)
    return formGroup;
  }


  
 getAllCountries() {
   //API call
   this.countries = [{"country":"United States","countryCode":"US"},{"country":"Canada","countryCode":"CA"}]
 }
  

  ngOnInit() {
    this.getAllCountries()
    const initData = [
      {countryCode: "US", stateCode: "AZ", fileNumber: "AAA"},
      {countryCode: "CA", stateCode: null, fileNumber: null}
    ]

    this.initFormArray(initData)
  }

}
1
  • 1
    Updated the post with my code. same available in stackblitz. Commented Sep 24, 2020 at 4:56

1 Answer 1

1

I symplified you scripts and seems work as due. But it's not finish - all may be done much more pretty. Pay attention to the formation html part - [formGroupName]="i" and how to work with formArray variable.

//html
<form [formGroup]="entityForm">
  <div formArrayName="optionGroups" class="ui-g ui-g-12 ui-g-nopad">
    <ng-container *ngFor="let item of optionGroups.controls; let i = index;" [formGroupName]="i">
      <div style="width: 100%; display: flex; margin-bottom:10px" class="ui-g  ui-g-12 ui-g-nopad">
        <div class="ui-md-4">
          <label class="mandatory">Country <span class="colon"></span></label>
          <select 
            formControlName="country"
            class="ui-inputtext" 
            (change)="onCountryChange(item.get('country').value, i)" 
            > 
            <option>--Select--</option>
            <option *ngFor="let c of countries" [ngValue]="c.countryCode">{{c.country}}</option>                 
          </select>
        </div>

        <div class="ui-md-4">
          <label class="lbl-hidden"> State </label>
          <select formControlName="state" class="ui-inputtext"> 
            <option>--Select--</option>
            <option *ngFor="let state of getStates(item.controls['country'].value)" [ngValue]="state.code">{{state.state}}</option>
          </select>
        </div>

        <div class="ui-md-3">
          <label class="lbl-hidden"> Number </label>
          <input
            type="text"
            pInputText
            class="form-control"
            formControlName="place"    
          />
        </div>
        <div class="ui-md-1">     
          <button (click)='removeOptionGroup(i)'  style="min-width: auto;"  pButton icon="fa fa-minus">Remove</button>
        </div>
      </div>
    </ng-container>
  </div>
</form>
<button class="add-remove-btn" pButton (click)='addOptionGroup()' icon="fa fa-plus">Add</button>

//ts
public countryOptions:any = [];
  public stateOptions:any = [];

  public countries = [];
  public states = [];

  public entityForm: FormGroup;
  public optionGroups: FormArray;

  constructor(
    private fb: FormBuilder
    ) {}

  ngOnInit() {
    this.entityForm = this.fb.group({
      optionGroups : this.fb.array([])
    });

    this.optionGroups = this.entityForm.get('optionGroups') as FormArray;

    this.getAllCountries();
    const initData = [
      {countryCode: "US", stateCode: "AZ", fileNumber: "AAA"},
      {countryCode: "CA", stateCode: null, fileNumber: null}
    ]

    this.initFormArray(initData)
  }


  public addOptionGroup(){
    const fa = this.entityForm.get('optionGroups') as FormArray;
    //fa.setValue("--Select--");
    fa.push(this.newOptionGroup());
  }

  public removeOptionGroup(index: number){

      const fa = this.entityForm.controls["optionGroups"] as FormArray;
    
      fa.removeAt(index);
    
      }

  onCountryChange(selectedCountry: string , formIndex : number) : void {
    console.log(selectedCountry);
    this.states[selectedCountry] = this.getStates(selectedCountry)
  }

  private newOptionGroup() {
    return new FormGroup({          
        country: new FormControl("--select--"),
        state: new FormControl("--select--"),
        place: new FormControl("GGG"),

    });
  }


  getStates(selectedCountry) {
    //API call

      switch(selectedCountry) {
        case "US" : 
          this.stateOptions =[
        {id: 14, state: "Alabama", code: "AL", countryCode: "US"},
        {id: 15, state: "Alaska", code: "AK", countryCode: "US"},
        {id: 17, state: "Arizona", code: "AZ", countryCode: "US"},
        {id: 18, state: "Arkansas", code: "AR", countryCode: "US"},
        {id: 19, state: "California", code: "CA", countryCode: "US"}
        ]
        break;

      case  "CA" :
        this.stateOptions =[{id: 37, state: "Marshall Islands", code: "MH", countryCode: "CA"},
        {id: 4, state: "New Brunswick", code: "NB", countryCode: "CA"},
        {id: 5, state: "Newfoundland and Labrador", code: "NL", countryCode: "CA"},
        {id: 53, state: "Northern Mariana Islands", code: "MP", countryCode: "CA"},
        {id: 6, state: "Northwest Territories", code: "NT", countryCode: "CA"}]
        break;    
      default: 
      this.stateOptions =[
        {id: 14, state: "Alabama", code: "AL", countryCode: "US"},
        {id: 15, state: "Alaska", code: "AK", countryCode: "US"},
        {id: 17, state: "Arizona", code: "AZ", countryCode: "US"},
        {id: 18, state: "Arkansas", code: "AR", countryCode: "US"},
        {id: 19, state: "California", code: "CA", countryCode: "US"}
        ]
        break;
    }
    return this.stateOptions;
  }

  initFormArray(initForm:any) {
    console.log(initForm);
    initForm.map((item, index) => {
      this.optionGroups.push(this.createForms(item, index));
    });
  }

  createForms(adresse, index): FormGroup {   
    const formGroup = new FormGroup({
        country: new FormControl(adresse.countryCode),
        state: new FormControl(adresse.stateCode),
        place: new FormControl(adresse.fileNumber)
      });
    this.onCountryChange(adresse.select1, index);
  return formGroup;
  }

  getAllCountries() {
    //API call
    this.countries = [{"country":"United States","countryCode":"US"},{"country":"Canada","countryCode":"CA"}]
  }
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.