Updating the FormArray index using Angular's `removeAt(i)` function does not reflect changes in the DOM

I initially suspected that there was an issue with my implementation, but it appears that the code I used to create a dynamic FormArray should be working, as indicated in this question I posted. However, when I integrate it into my project, the remove function successfully deletes the element from the FormArray, but the change is not reflected in the interface or the DOM. What could be causing this?

import {
  Component,
  VERSION
} from '@angular/core';
import {
  FormGroup,
  FormControl,
  FormArray,
  Validators,
  FormBuilder
} from '@angular/forms';

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {

  objectProps: any[];

  public dataObject = [{
      "label": "Name",
      "name": "name",
      "type": "text",
      "data": ""
    },
    {
      "label": "Contacts",
      "name": "contacts",
      "type": "inputarray",
      "array": []
    }
  ]
  form: FormGroup;

  constructor(private _fb: FormBuilder) {}

  ngOnInit() {

    const formGroup = {};
    for (let field of this.dataObject) {
      if (field.type == "inputarray") {
        console.log("THIS IS " + field.type)
        formGroup[field.name] = this._fb.array([''])
      } else {
        console.log("THIS IS " + field.type)
        formGroup[field.name] = new FormControl(field.data || '') //, this.mapValidators(field.validation));
      }
    }

    this.form = new FormGroup(formGroup);
  }

  addFormInput(field) {
    const form = new FormControl('');
    ( < FormArray > this.form.controls[field]).push(form);
  }

  removeFormInput(field, i) {
    ( < FormArray > this.form.controls[field]).removeAt(i);
  }
}
<form *ngIf="form" novalidate (ngSubmit)="onSubmit(form.value)" [formGroup]="form">
  <div *ngFor="let field of dataObject">
    <h4>{{field.label}}</h4>
    <div [ngSwitch]="field.type">
      <input *ngSwitchCase="'text'" [formControlName]="field.name" [id]="field.name" [type]="field.type" class="form-control">
      <div *ngSwitchCase="'inputarray'">
        <div formArrayName="{{field.name}}" [id]="field.name">
          <div *ngFor="let item of form.get(field.name).controls; let i = index;" class="array-line">
            <div>
              <input class="form-control" [formControlName]="i" [placeholder]="i">
            </div>
            <div>
              <button id="btn-remove" type="button" class="btn" (click)="removeFormInput(field.name, i)">x</button>
            </div>
          </div>
        </div>
        <div>
          <button id="btn-add" type="button" class="btn" (click)="addFormInput(field.name)">Add</button>
        </div>
      </div>
    </div>
  </div>
  <button type="submit" class="btn btn-danger btn-block" style="float: right; width:180px" [disabled]="!form.valid">Save</button>

Answer №1

After encountering a problem, I came up with a slightly unconventional solution that involved manipulating the values and removing a control. It might not be the best approach, but it worked for me.

My method involved moving the item I wanted to remove to the end of the array and then deleting the last item.

removeItem(index: number): void {
  const value = this.formArray.value;

  this.formArray.setValue(
    value.slice(0, index).concat(
      value.slice(index + 1),
    ).concat(value[index]),
  );

  this.formArray.removeAt(value.length - 1);
}

I believe this solution could potentially benefit others facing the same issue down the line.

Answer №2

If you're looking to trigger change detection by referencing the application object, you can inject the ApplicationRef in your constructor and call the tick(); method within your removeFormInput function.

constructor(private _fb: FormBuilder, private appRef: ApplicationRef) {}

Within the removeFormInput function:

removeFormInput(field, i) {
    (<FormArray>this.form.controls[field]).removeAt(i);
    this.appRef.tick();
}

For more information, refer to the Angular documentation: API > @angular/core /ApplicationRef.tick()

Answer №3

I encountered a similar issue. The solution that worked for me was removing or fixing the trackBy function within NgFor*. Implementing a proper trackBy function could potentially resolve the error you are facing.

source: How to utilize `trackBy` in conjunction with `ngFor`

Answer №4

It is important to update the function below, as the row object is not being removed from the 'dataObject'.

deleteFormInput(field, index) {
    ( < FormArray > this.form.controls[field]).removeAt(index);
    this.dataObject.splice(this.dataObject.indexOf(field),1);
  }

Check out this Stackblitz demo I created, where you can add and remove form items successfully. Take a look at it.

Working version available here

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

When implementing asynchronous form control validation in Angular 2, several API requests are triggered

Can anyone help me with adding async validation using a FormControl? For every keypress, I am receiving multiple responses and it seems like an extra request is triggered whenever I type or remove a character in the form control. code-snippets.component.t ...

Should I utilize Sockets or Ajax for my project?

My Login Script Journey I have a goal in mind - to create a login script using Nodejs. I am currently exploring the options of utilizing sockets or ajax posts for this task. My Progress So Far I have Nodejs installed and have referenced this code in my ...

Error messages are being generated by Angular CLI due to an unclosed string causing issues with the

After incorporating styles from a Bootstrap theme into my Angular 8 project and updating angular.json, I encountered a compile error displaying the following message: (7733:13) Unclosed string 7731 | } 7732 | .accordion_wrapper .panel .panel-heading ...

Discover the simple steps to generating dynamic variables with jQuery!

I am looking to dynamically create jQuery variables based on values in a loop. Here is an example of what I am trying to achieve. array=["student","parent","employee"] $.each(user_types, function( index, value ){ var dynamicType = value + "_type"; // t ...

Performing inner joins on 2 tables using Mongoose

My inner join query seems to be resulting in a left join unexpectedly. I have 2 tables with relations and I'm trying to retrieve movies along with their genre names. Here are the models I'm working with: // Movie const MovieSchema = new mongoose ...

Accessing dynamically inserted child components in Angular 2.0

Currently, I am utilizing this sample to dynamically generate components within my application. export class App { @ViewChild('placeholder', {read: ViewContainerRef}) viewContainerRef; private componentFactory: ComponentFactory<any> ...

"Optimizing Performance: Discovering Effective Data Caching

As a developer, I have created two functions - one called Get to fetch data by id from the database and cache it, and another called POST to update data in the database. However, I am facing an issue where I need to cache after both the get and update oper ...

ng-repeat table grouping by date

How can I utilize *ngFor to generate an HTML table grouped by date in columns? Here is an example of a JSON List: [{ "id": "700", "FamilyDesc": "MERCEDES", "model": "Mercedes-BenzClasse A", " ...

Are current web browsers able to block the code "<a href="javascript:window.open....?

I am looking to create a pop-up window for sharing on Facebook. The best way to achieve this is by using javascript to pop up a small window with a width of 400 pixels and a height of 200 pixels. Will pop-up blockers in Chrome, IE, or Google block this f ...

Modify the fixed div's class when the user scrolls past a certain section

My page includes a fixed menu with various sections, each assigned a specific class name using data attributes (e.g. data-menu="black"). I want the fixed menu to change its class based on the section that is currently underneath it as the user scrolls. Y ...

Restangular failing to apply headers during post requests

I have been encountering an issue while trying to set the header for a single post request using Restangular. Despite following the documentation here and seeking help from a similar question, the request is being sent as plain text instead of JSON. My se ...

Displaying a div in Vue.js when a button is clicked and an array is filled with

Hey there! I'm having an issue with displaying weather information for a specific location. I want to show the weather details in a div only when a button is clicked. Despite successfully fetching data from the API, I'm struggling to hide the wea ...

Retrieve the service variable in the routing file

How do I access the service variable in my routing file? I created a UserService with a variable named user and I need to use that variable in my routing file. Here is the approach I tried, but it didn't work: In the routing file, I attempted: cons ...

Determine the available time slots for reserving a resource

I am developing an application that displays the weekly availability (Monday-Sunday) of a bookable resource. Next to this calendar view, users can select: A) Length of desired booking slot (15 min/30 min/60 min) B) Time zone The time slots are based ...

What is the best approach to simultaneously update an array using multiple threads in a Node.js environment?

Hey there, I'm trying to figure out how to make changes to the same array using 2 worker threads in Node.js. Can anyone help me with this? My issue is that when I add a value in worker thread 1 and then try to access it in worker thread 2, the second ...

Unexpected issue with AngularJS Select2 multiple feature: ng-selected not functioning as expected

I have been working with the code below to select an item if it is present in the filters: <div ng-repeat="category in categories.data" ng-model="div1"> <div ng-repeat="(key, value) in category" mg-model="div1.div2"> ...

ngx-translate: comparing pipes and directives

I recently integrated the ngx-translate i18n module from GitHub and encountered some unexpected behavior. <span [translate]="'HELLO'"></span> When using the directive, the translation only works once and does not update if I switch ...

Is it possible to determine when a component has completed its rendering process in Angular?

I am currently working on an Angular application where I have a page component that contains several subcomponents. Each subcomponent is set up to fetch data from an API in the ngOnInit method, causing a layout shift issue as they load at different speeds ...

Changing text content into objects in Protractor

I am facing an issue with a span tag that contains JSON text, which I need to convert into an object in Protractor for testing purposes. {"type":"msax-cc-error","value":[{"Code":22104,"Message":"Card holder is required"},{"Code":22058,"Message":"Card numb ...

Tips for Emphasizing a Row in a Table Using a Specific Value

Currently, I am engaged in creating an educational YouTube tutorial that delves into Google App Script and Google Sheets. I have been attempting various methods to highlight a row containing the word "ABSENT", but all my endeavors have proven to be unsucc ...