Trigger selectionchange event from formArray control typescript

67 Views Asked by At

I'm having a dynamic form with cascading dropdowns. When the page loads, I assign the values to the controls, but the selectionchange event isn't triggered.

HTML:

<div formArrayName="userDataAttributes" *ngFor="let other of userForm.get('userDataAttributes')['controls']; let i = index" class="form-group">
                    <div [formGroupName]="i">
                      {{i + 1}}.
                      <mat-form-field> 
                        <mat-select matInput placeholder="Select Data Attribute" formControlName="dataAttributeId" matNativeControl (selectionChange)="refreshUserDataAttributeValuesByAttrId($event.value, i);">
                          <mat-option *ngFor="let attr of List1" [value]="attr.dataAttributeId">{{attr.dataAttributeName}}</mat-option>
                        </mat-select>
                      </mat-form-field>
                      <mat-form-field>
                        <mat-select matInput multiple formControlName="dataAttributeValues" matNativeControl>
                          <mat-option *ngFor="let attr of List2[i]" [value]="attr.dataAttributeValueId">{{attr.dataAttributeValue}}</mat-option>
                        </mat-select>
                      </mat-form-field>
                    </div>
                  </div>

Typescript:

refreshUserDataAttributeValuesByAttrId(attributeId: number, index: number) {
    if (attributeId && attributeId > 0) {

      this.List2[index] = this.List1?.filter(a => a.dataAttributeId === attributeId) ?? [];
    }
    else {
      this.List2[index]= [];
    }
  }

  addUserDataAttributes(dataAttributeId: number, dataAttributeValues: any ): FormGroup{
    return this.formBuilder.group({
      dataAttributeId: [dataAttributeId],
      dataAttributeValues: [dataAttributeValues]
    });
  }


bindValuesToDynamicForm(){
array: any=[{
dataAttributeId: 1,
dataAttributeValues: "4,5"},
{
dataAttributeId: 2,
dataAttributeValues: "2,3"}]

    array.forEach((x,i)=>{ (<FormArray>this.userForm.get('userDataAttributes')).push(this.addUserDataAttributes(x.dataAttributeId, x.dataAttributeValues.split(',')));
    })
  }

With the above code,the first dropdown dataAttributeId gets loaded correctly but couldn't trigger the selectionChange of that control so it refreshes the dataAttributeValues control and sets the value.

Tried,

  this.refreshUserDataAttributeValuesByAttrId(x.dataAttributeId, i);

Any help?

1

There are 1 best solutions below

0
José Matos On

The way to solve this is to manually call the refreshUserDataAttributeValuesByAttrId method after you set the value of your dataAttributeId control. You can do this in your bindValuesToDynamicForm method where you are iterating over your array and setting the values.

Here’s how you can do it:

bindValuesToDynamicForm() {
  const array: any = [
    { dataAttributeId: 1, dataAttributeValues: "4,5" },
    { dataAttributeId: 2, dataAttributeValues: "2,3" }
  ];

  const userDataAttributesFormArray = <FormArray>this.userForm.get('userDataAttributes');

  array.forEach((x, i) => {
    userDataAttributesFormArray.push(this.addUserDataAttributes(x.dataAttributeId, x.dataAttributeValues.split(',')));

    // Manually call the method to refresh the List2 array at the current index
    this.refreshUserDataAttributeValuesByAttrId(x.dataAttributeId, i);
  });
}

After pushing a new group into your form array, the refreshUserDataAttributeValuesByAttrId method is called with the current dataAttributeId and index, which should update your List2 array as expected.

However, setting the values for dataAttributeValues control won't be enough because the values from array are strings and the values in your mat-option are probably different objects. You need to find the correct objects from List2[i] to set as the values for your dataAttributeValues control.

To set the correct values, you might need to modify your addUserDataAttributes method to find the correct objects from List2[i] to set as the default values for your dataAttributeValues control. You would do this after the List2[i] array is populated by the refreshUserDataAttributeValuesByAttrId method.

Here is a rough idea of how you might do this:

addUserDataAttributes(dataAttributeId: number, dataAttributeValues: any, index: number): FormGroup {
  // Find the correct objects from List2 to set as the default values
  const correctDataAttributeValues = this.List2[index]?.filter(attr => dataAttributeValues.includes(attr.dataAttributeValueId)) || [];
  
  return this.formBuilder.group({
    dataAttributeId: [dataAttributeId],
    dataAttributeValues: [correctDataAttributeValues]
  });
}

In your bindValuesToDynamicForm method, update the call to addUserDataAttributes to pass the index as well:

userDataAttributesFormArray.push(this.addUserDataAttributes(x.dataAttributeId, x.dataAttributeValues.split(','), i));