Search code examples
javascriptangularangular2-formsangular5angular4-forms

Angular 5 formBuilder - Nested Array and For loop


Im working on a profile editing page in an ionic app everything works as fine with all the top level items of the users profiles info (name, email, sex etc..)

I have hobbies stored in an array off this main json node (using Firestore) so its 1 level deep off the main node..

I cant seem to figure out how to use form builder with it. I suspect I am going wrong on 2 points, 1 being how I am using formbuilder and 2 on the merge fuction as it doesnt take into account nested structures which I am also unsure how to approach.. any help would be awesome.

  _buildForm() {

    this.form = this.formBuilder.group({
      displayName: [this.options.displayName] || '',
      dob: [this.options.dob] || '',
      sex: [this.options.sex] || '',
      city: [this.options.city] || '',
      country: [this.options.country] || '', 
      bio: [this.options.bio] || '',   
      hobbies: this.formBuilder.group( this.options.hobbies )  
    });

    // Watch the form for changes, and
    this.form.valueChanges.subscribe((v) => {
      this.merge(this.form.value);
    });
  }  


  merge(settings: any) {

    for (let k in settings) {
      this.settings[k] = settings[k];
    }
    return this._save();
  }


  _save() {
     // this function then save the data back to firestore using a simple update of the entire json output
  }

Solution

  • You need these

     _buildForm() {
        this.form = this.formBuilder.group({
          displayName: [this.options.displayName] || '',
          dob: [this.options.dob] || '',
          sex: [this.options.sex] || '',
          city: [this.options.city] || '',
          country: [this.options.country] || '', 
          bio: [this.options.bio] || '',   
          hobbies: this.formBuilder.group([])  
        });
        if(this.options.hobbies.length>0){
          this._setHobbiesForm(this.options.hobbies);
        }
      }  
    
      //To build the hobby gorm
      _buildHobbyForm(hobby) {
        var hobbyForm = this.fb.group({
          Name: hobby.Name||''
        });
        return hobbyForm ;
      }
    
      //To attach the hobbies form with data back to main form
      _setHobbiesForm(hobbies) {
        const hobbiesFGs = hobbies.map(hobby=> this._buildHobbyForm(hobby));
        const hobbiesFR = this.fb.array(hobbiesFGs);
        this.form.setControl('hobbies', hobbiesFR);
      }
    
     //To get form values for saving
     _prepareSaveInfo(){
        const formModel = this.form.value;
        //deep copy of hobbies
        const hobbiesDeepCopy= formModel.hobbies.map(
          (hobby) => Object.assign({}, hobby)
        );
        const profile={
          displayName: formModel.displayName as string,
          sex: formModel.sex as string,
          dob: formModel.dob as string,
          city: formModel.city as string,
          country: formModel.country as string,
          hobbies:hobbiesDeepCopy
        }
        return profile;
      }
    
      _save() {
        let dataToSave=this._prepareSaveInfo();
        console.log(dataToSave);
      }
    

    This is the way to handle array inside forms in angular , if it doesn't fits your code logic exactly , take it as a example and build your logic from it , definitely this example will help you .

    Iam posting an example for html also here (basically to show how to handle arrays inside the form in html)

    <div formArrayName="hobbies">
        <div *ngFor="let hobby of form.get('hobbies').controls; let i=index" [formGroupName]="i">
        <!-- your code for hobby-->
        </div>
    </div>