[Fixed] How do I pass down a custom string from typescript, in the formGroup, and read the value of it in *ngFor inside template?

Issue

Consider the following formArray excerpt inside the template:

<div class="p-col-12 controls-div" formArrayName="fields">
    <div
        class="p-grid"
        *ngFor="let item of getFieldControls(); let i = index"
        [formGroupName]="i"
        style="margin-top: 10px;">
        <div class="p-col-8">
            <!-- if string is Text -->
            <input
                *ngIf="string == 'Text'"
                type="text"
                pInputText
                formControlName="control">
            <!-- if string is number -->
            <input
                *ngIf="string == 'Number'"
                type="text"
                pInputText
                formControlName="control">
             <!-- if string is Yes/No -->
             <p-toggleButton
                *ngIf="string == 'Yes/No'" 
                onLabel="Yes" 
                offLabel="No" 
                formControlName="control"></p-toggleButton>
        </div>
        <div class="p-col-2">
        <button
            type="button"
            class="btn btn-danger"
            (click)="onDeleteField(i)">X</button>
        </div>
    </div>                        
</div>

I want to pass down a string from my getFieldControls() method and bind to the control, in the *ngFor loop, to the correct "type of control" (element). My problem is I tried a 100 different ways to pass this string. I tried adding a data-type attribute like so:

(<FormArray>this.itemForm.get('fields')).push(
        new FormGroup({
          'control': new FormControl(
            {data-type: 'number', value:variable.name, disabled:true}, [Validators.required])
        })
      );

I then wanted to read it, in template, like so:

*ngIf="item[0].control.data-type == 'text'"

but the compiler complained. It seems that I can only pass down value and disabled. Later on I tried setting a value to the formgroup, also no luck. If I can pass a string I would know which control to load into the DOM in the template. I also tried to add the element directly, dynamically, from typescript like so:

<div [innerHTML]="elementToAdd"></div>

and in typescript

if (this.type == 'number') {
    elementToAdd += '<input type="number" ...>';
}

When I did this, every time a add a control the I added like 4 or 8 controls. At the end of the day I would get a, lets say ‘dropdown’, value (string) in the template and *ngIf only the dropdown and then bind to it.

I use an array to find, based on an id, which type of control to load. My method to push a new control looks like so:

onAddField(id: string) {
    let variable = this.variables.find(i => i.id === id);
    
    if (variable?.control == 'Text') {
      //add an Input
      (<FormArray>this.itemForm.get('fields')).push(
        new FormGroup({
          'control': new FormControl(
            {value:variable.name, disabled:true}, Validators.required)
        })
      );
    }
    if (variable?.control == 'Number') {
      //add an Input
      (<FormArray>this.itemForm.get('fields')).push(
        new FormGroup({
          'control': new FormControl(
            {value:variable.name, disabled:true}, Validators.required)
        })
      );
    }
    //somewhere in the formgroup or formcontrol I want to pass a string so that I can know which form control to load, using *ngIf,in the template.
  }

I init my form like so:

this.itemForm = new FormGroup({
  fields: new FormArray([])
});

And to get the controls, here is my method:

getFieldControls() {
  let controls = (this.itemForm.get('fields') as FormArray).controls;
  return controls;
}

Solution

you can do it that way.

<div class="p-col-12 controls-div" formArrayName="fields">
    <div
        class="p-grid"
        *ngFor="let item of getFieldControls(); let i = index"
        [formGroupName]="i"
        style="margin-top: 10px;">
          <div class="p-col-8">
            <!-- if string is Text -->
            <input
                *ngIf="typeList[index] == 'Text'"
                type="text"
                pInputText
                formControlName="control">
            <!-- if string is number -->
            <input
                *ngIf="typeList[index] == 'Number'"
                type="text"
                pInputText
                formControlName="control">
             <!-- if string is Yes/No -->
             <p-toggleButton
                *ngIf="typeList[index] == 'Yes/No'" 
                onLabel="Yes" 
                offLabel="No" 
                formControlName="control"></p-toggleButton>
        </div>
        <div class="p-col-2">
        <button
            type="button"
            class="btn btn-danger"
            (click)="onDeleteField(i)">X</button>
        </div>
    </div>                        
</div>

and in onAddField() you can do it as. because I think variable is somewhat relevant here.

typeList: stringp[] = [];
onAddField(id: string) {
    let variable = this.variables.find(i => i.id === id);
    this.typeList.push(variable?.control)
    
    if (variable?.control == 'Text') {
      //add an Input
      (<FormArray>this.itemForm.get('fields')).push(
        new FormGroup({
          'control': new FormControl(
            {value:variable.name, disabled:true}, Validators.required)
        })
      );
    }
    if (variable?.control == 'Number') {
      //add an Input
      (<FormArray>this.itemForm.get('fields')).push(
        new FormGroup({
          'control': new FormControl(
            {value:variable.name, disabled:true}, Validators.required)
        })
      );
    }
    //somewhere in the formgroup or formcontrol I want to pass a string so that I can know which form control to load, using *ngIf,in the template.
  }

Leave a Reply

(*) Required, Your email will not be published