最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How to add dynamic input fields to angular form using array from http request - Stack Overflow

programmeradmin3浏览0评论

I have tried all methods and checked related stackoverflow questions and nothing worked so asking here. I have to create ui where on select of dropdown an api call is made and data is received in form of an array . Based on this array i want to add as many fields to my form as there are number of elements in array. I tried using FormArray but it did not work. As i keep getting error related to cannot find control with specified name 'name'. I tried using making formcontrol fields dynamic but still getting the same error.

Here is the code that i tried .

.ts file

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormControl, FormArray } from '@angular/forms';
import { HttpClient } from '@angular/mon/http';

@Component({
  selector: 'app-calculator',
  templateUrl: './calculatorponent.html',
  styleUrls: ['./calculatorponent.scss']
})
export class CalculatorComponent implements OnInit {

  title = 'Formula Calculation Page';
  configUrlProducts = 'http://localhost:3000/data/products';
  configUrlProductFieldsData = 'http://localhost:3000/data/getproductfields/';

  angForm: FormGroup;
  ruleset_data=[];
  ruleset_data_length=0;
  products: any = [];
  selected_product_id;
  syntax_error=false
  show_form=false;
  arr=[{'name':''},{'class':''},{'tree':''}];
  temp;

 //  products=[{"id":1,"name":'Product 1'},{"id":2,"name":'Product 2'},{"id":3,"name":'Product 3'}]
  constructor(private fb: FormBuilder,private http: HttpClient) {
   console.log("inside constructor")
  //  this.createForm();
   // this.fetch_products();
  }
     // convenience getters for easy access to form fields
     get f() { return this.angForm.controls; }
     get t() { return this.f.fields as FormArray; }


 ngOnInit() {
   console.log("inside ngonit");
  this.angForm = this.fb.group({
    fields: new FormArray([])
  });

  for(var i=0;i<3;i++){
    this.temp=this.arr[i];
    this.t.push(this.fb.group({'name':''}))
  }

  // this.arr.forEach(item=>{
  //   this.t.push(this.fb.group(item))
  // })
  console.log(this.angForm)
   this.getProducts();
 }

 getProducts() {
   console.log("inside get products");
   this.products = [];
   this.http.get(this.configUrlProducts).subscribe((res)=>{
     console.log(res);
     this.products = res["data"];
   });
 }


 fetch_ruleset_data(value: string){
   this.selected_product_id=value;
   console.log("inside get rule data");
   this.ruleset_data = [];
   this.http.get(this.configUrlProductFieldsData+value).subscribe((res)=>{
     console.log(res);
     this.ruleset_data = res["data"];

     this.show_form=true;
      console.log(this.angForm);
     this.ruleset_data_length=res["data"].length;
   });
 }

 onSubmit(value){
   console.log(value);
  //  var data=value;
  //  data["no_of_variables"]=this.ruleset_data_length;
  //  data["product_id"]=this.selected_product_id;
  //  // value=value+this.ruleset_data_length;
  //  // var formula=JSON.parse(value);
  //  console.log("final data before sending to api",data);
  //  return this.http.post('http://localhost:3000/formula/addformula', data)
  //  .subscribe((res)=>{
  //    console.log(res);
  //  })
 }

 validateFormula=(c: FormControl)=> {
   console.log(c.value,typeof c.value);
   var data={};
   data['formula']=c.value;
   data["no_of_variables"]=this.ruleset_data_length;
   data["product_id"]=this.selected_product_id;

   return this.http.post('http://localhost:3000/formula/validateformula', data)
   .subscribe((res)=>{
     // console.log("inside validation after api call",res)
     // console.log(res["error"])
     if(res["error"]){
       console.log("inside error block",res);
       this.syntax_error=true;
       // this.angForm.setErrors({ 'invalid': true });
       // return true;

       return {
         validateFormula: {
           valid: true
         }
       }
     }else{
       this.syntax_error=false;
       // this.angForm.setErrors({ 'invalid': false });
       // return true;
       return {
         validateFormula: {
           valid: true
         }
       }
     }
   })

   // let EMAIL_REGEXP;

   // return EMAIL_REGEXP.test(c.value) ? null : {
   //   validateEmail: {
   //     valid: false
   //   }
   // };
 }


 // fetch_ruleset_data(value: string){
 //   console.log(value);
 // }




}

.html file

<!-- appponent.html -->

<div class="container">
        <h1>
          Wele to {{title}}!!
        </h1>

        <select class="custom-select" (change)="fetch_ruleset_data($event.target.value)">
                <option value="" disabled>Choose your product</option>
                <option *ngFor="let product of products; let i = index" [value]="product.id">
                  {{product.name}}
                </option>
        </select>



        <div *ngIf="show_form==true">
        <form [formGroup]="angForm" (ngSubmit)="onSubmit(angForm.value)">
                <div *ngFor="let item of t.controls; let i = index">
                  <div [formGroup]="item">
                    <input [formControlName]='item'>
                  </div>
                </div>
                <button type="submit">Submit</button>
        </form>


        </div>
        <br />

</div>

Have been struggling with this from past 2 days any help is greatly appreciated. I am new to angular and currently learning it it might be a simple thing but i am unable to figure it out at present and need your help.

I have tried all methods and checked related stackoverflow questions and nothing worked so asking here. I have to create ui where on select of dropdown an api call is made and data is received in form of an array . Based on this array i want to add as many fields to my form as there are number of elements in array. I tried using FormArray but it did not work. As i keep getting error related to cannot find control with specified name 'name'. I tried using making formcontrol fields dynamic but still getting the same error.

Here is the code that i tried .

.ts file

import { Component, OnInit } from '@angular/core';
import { FormGroup, FormBuilder, Validators, FormControl, FormArray } from '@angular/forms';
import { HttpClient } from '@angular/mon/http';

@Component({
  selector: 'app-calculator',
  templateUrl: './calculator.ponent.html',
  styleUrls: ['./calculator.ponent.scss']
})
export class CalculatorComponent implements OnInit {

  title = 'Formula Calculation Page';
  configUrlProducts = 'http://localhost:3000/data/products';
  configUrlProductFieldsData = 'http://localhost:3000/data/getproductfields/';

  angForm: FormGroup;
  ruleset_data=[];
  ruleset_data_length=0;
  products: any = [];
  selected_product_id;
  syntax_error=false
  show_form=false;
  arr=[{'name':''},{'class':''},{'tree':''}];
  temp;

 //  products=[{"id":1,"name":'Product 1'},{"id":2,"name":'Product 2'},{"id":3,"name":'Product 3'}]
  constructor(private fb: FormBuilder,private http: HttpClient) {
   console.log("inside constructor")
  //  this.createForm();
   // this.fetch_products();
  }
     // convenience getters for easy access to form fields
     get f() { return this.angForm.controls; }
     get t() { return this.f.fields as FormArray; }


 ngOnInit() {
   console.log("inside ngonit");
  this.angForm = this.fb.group({
    fields: new FormArray([])
  });

  for(var i=0;i<3;i++){
    this.temp=this.arr[i];
    this.t.push(this.fb.group({'name':''}))
  }

  // this.arr.forEach(item=>{
  //   this.t.push(this.fb.group(item))
  // })
  console.log(this.angForm)
   this.getProducts();
 }

 getProducts() {
   console.log("inside get products");
   this.products = [];
   this.http.get(this.configUrlProducts).subscribe((res)=>{
     console.log(res);
     this.products = res["data"];
   });
 }


 fetch_ruleset_data(value: string){
   this.selected_product_id=value;
   console.log("inside get rule data");
   this.ruleset_data = [];
   this.http.get(this.configUrlProductFieldsData+value).subscribe((res)=>{
     console.log(res);
     this.ruleset_data = res["data"];

     this.show_form=true;
      console.log(this.angForm);
     this.ruleset_data_length=res["data"].length;
   });
 }

 onSubmit(value){
   console.log(value);
  //  var data=value;
  //  data["no_of_variables"]=this.ruleset_data_length;
  //  data["product_id"]=this.selected_product_id;
  //  // value=value+this.ruleset_data_length;
  //  // var formula=JSON.parse(value);
  //  console.log("final data before sending to api",data);
  //  return this.http.post('http://localhost:3000/formula/addformula', data)
  //  .subscribe((res)=>{
  //    console.log(res);
  //  })
 }

 validateFormula=(c: FormControl)=> {
   console.log(c.value,typeof c.value);
   var data={};
   data['formula']=c.value;
   data["no_of_variables"]=this.ruleset_data_length;
   data["product_id"]=this.selected_product_id;

   return this.http.post('http://localhost:3000/formula/validateformula', data)
   .subscribe((res)=>{
     // console.log("inside validation after api call",res)
     // console.log(res["error"])
     if(res["error"]){
       console.log("inside error block",res);
       this.syntax_error=true;
       // this.angForm.setErrors({ 'invalid': true });
       // return true;

       return {
         validateFormula: {
           valid: true
         }
       }
     }else{
       this.syntax_error=false;
       // this.angForm.setErrors({ 'invalid': false });
       // return true;
       return {
         validateFormula: {
           valid: true
         }
       }
     }
   })

   // let EMAIL_REGEXP;

   // return EMAIL_REGEXP.test(c.value) ? null : {
   //   validateEmail: {
   //     valid: false
   //   }
   // };
 }


 // fetch_ruleset_data(value: string){
 //   console.log(value);
 // }




}

.html file

<!-- app.ponent.html -->

<div class="container">
        <h1>
          Wele to {{title}}!!
        </h1>

        <select class="custom-select" (change)="fetch_ruleset_data($event.target.value)">
                <option value="" disabled>Choose your product</option>
                <option *ngFor="let product of products; let i = index" [value]="product.id">
                  {{product.name}}
                </option>
        </select>



        <div *ngIf="show_form==true">
        <form [formGroup]="angForm" (ngSubmit)="onSubmit(angForm.value)">
                <div *ngFor="let item of t.controls; let i = index">
                  <div [formGroup]="item">
                    <input [formControlName]='item'>
                  </div>
                </div>
                <button type="submit">Submit</button>
        </form>


        </div>
        <br />

</div>

Have been struggling with this from past 2 days any help is greatly appreciated. I am new to angular and currently learning it it might be a simple thing but i am unable to figure it out at present and need your help.

Share Improve this question edited Dec 12, 2019 at 8:29 georgeawg 49k13 gold badges77 silver badges98 bronze badges asked Dec 12, 2019 at 6:52 user7760120user7760120 1
  • Hello Please paste your code here stackblitz. and make it work, in this way it'd much easer to help – Lasha Sumbadze Commented Dec 12, 2019 at 7:28
Add a ment  | 

2 Answers 2

Reset to default 2

You can use FormArray and FormGroup to get desired result.

An example can be seen at stackblitz.

HTML:

<form [formGroup]="myForm">
    <ng-container *ngFor="let group of myForm.controls |keyvalue">

    <div [formGroup]="group.value">        
        <button type="button" (click)="onAddProduct(group.value)">Add Product</button>
        <div formArrayName="productList">
            <div *ngFor="let item of productArray(group.value).controls; let i = index">
                  <label for="">Your row</label>
                  <input [formControlName]="i">
                  <button (click)="removeProduct(group.value,i)">remove</button>
            </div>
        </div> 
    </div>
<pre>
{{myForm?.value|json}}
</pre>
    </ng-container>
</form>

TypeScript:

name = 'Angular';
public myForm: FormGroup;

ngOnInit() {
    this.myForm = new FormGroup({});
    for(let item of ['item1']) {
        this.myForm.addControl(item,
            new FormGroup({
                name: new FormControl(),
                productList: new FormArray([])
            })
         )
     }  
  } 

onAddProduct(group:FormGroup) {
    (group.get('productList') as FormArray).push(new FormControl())
}

productArray(group:FormGroup):FormArray
{
    return group.get('productList') as FormArray;
}

removeProduct(group:FormGroup,index:number)
{
    (group.get('productList') as FormArray).removeAt(index)
}

I don't know about the data you receivedImagine the data you received, your example show that is some like

[{'name':''},{'class':''},{'tree':''}];

Really is a terrible data. It's more "natural" received some like

[{col:'name',value:''},{col:'class',value:''},{col:'tree',value:''}];

But i supouse is another question. The "key" is create a FormGroup when received the data and (in your case, create an array with the name of the fields) iterate over the array

   this.http.get(this.configUrlProducts).subscribe((res:any[])=>{
     this.formGroup=new FormGroup({}) //<--create a formGroup empty
     this.fields=[] //<--create an array empty
     res.forEach(x=>{
       const key=Object.keys(x)[0]
       const value=x[key]
       this.formGroup.addControl(key,new FormControl(value))
       this.fields.push(key)
     })
   });

So, your .html can be like

<form [formGroup]="formGroup">
   <div *ngFor="let col of fields">
       <input [formControlName]="col">
   </div>
</form>

If the array you received is like "my natural" way, the function and the .html changes like

   this.http.get(this.configUrlProducts).subscribe((res:any[])=>{
     this.formGroup=new FormGroup({}) //<--create a formGroup empty
     res.forEach(x=>{
       const key=x.col
       const value=x.value
       this.formGroup.addControl(key,new FormControl(value))
     })
     this.fields=res;
   });

<form [formGroup]="formGroup">
   <div *ngFor="let field of fields">
       <input [formControlName]="field.col">
   </div>
</form>

This idea can scale if you received an array of object with name, value, validators, label... becaosue you can use,e.g. {{field.label}} to show the label

If you received ['a','b','c'] you can use

   this.http.get(this.configUrlProducts).subscribe((res:any[])=>{
     this.formGroup=new FormGroup({}) //<--create a formGroup empty
     res.forEach(x=>{
       this.formGroup.addControl(x,new FormControl(''))
     })
     this.fields=res;
   });

<form [formGroup]="formGroup">
   <div *ngFor="let field of fields">
       <input [formControlName]="field">
   </div>
</form>
发布评论

评论列表(0)

  1. 暂无评论