1

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/common/http';

@Component({
  selector: 'app-calculator',
  templateUrl: './calculator.component.html',
  styleUrls: ['./calculator.component.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.component.html -->

<div class="container">
        <h1>
          Welcome 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.

1

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>
  • i am getting data in form of ['a','b','c','d'] which represents the input fields for which i have to take input in the form – Yogesh Manjhi Dec 12 at 7:55
  • I just update my answer – Eliseo Dec 12 at 8:01
  • thanks it worked finally. I am a newbie with angular and was trying to get it working from past two days. Thanks a lot :) – Yogesh Manjhi Dec 12 at 8:44
0

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)
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.