-
Notifications
You must be signed in to change notification settings - Fork 27.1k
Description
🐞 bug report
Affected Package
@angular/forms
Is this a regression?
The issue is not a regression. It is applicable to all Angular versions.
Description
The problem arises in the template driven form (with NgModel) when you change the name attribute of the control in the DOM. If one has, say, 4 <input> fields in an ngFor loop with their own values and name attributes that correspond to the array’s indexes, and removes whichever <input> field but the last one, and then adds a new <input> field, the default value of the newly-added field replaces the value of the third <input> field. That is, the DOM element’s value is affected by the value of the newly-added field, whereas the values of the array elements behind the DOM elements are not.
The problem has to do with the FormControls in the FormGroup, related to the rendered DOM elements, and the naming convention for FormControls of using indexes. Removing an <input> DOM element does not change the names of the rest underlying FormControls within the FormGroup even if the name attribute of the control has been changed. It just reorganises the indexes of the DOM elements after the removed field. Thus, when a new <input> element is added after the removal of an element, its FormControl’s name is created with index 3, which is already used in the name of the FormControl for the second last element, and the new FormControl eventually points to the two last <input> DOM elements at the same time.
To sum up, we want to lay down the following two considerations. First, what is the reason for the NgModel not to follow the changes in the names of DOM elements and not to update FormControls in the FormGroup? Second, we know that trackBy solves our problem, as suggested in a number of posts online such as this one, but we believe that this is a workaround and the real issue is circumvented. That is why we would like to propose another solution with the following patch:
--- old_ng_model.js 2020-08-13 11:12:38.000000000 +0300
+++ ng_model.js 2020-08-13 11:03:54.000000000 +0300
@@ -151,6 +151,15 @@
this._checkForErrors();
if (!this._registered)
this._setUpControl();
+ if (this._registered && 'name' in changes && changes.name['previousValue']){
+ resolvedPromise.then(() => {
+ let currControl = Object.assign(new NgModel, this);
+ currControl.name = changes.name['previousValue'];
+ return this.formDirective.removeControl(currControl);
+ }).then(() => {
+ this._setUpControl();
+ });
+ }
if ('isDisabled' in changes) {
this._updateDisabled(changes);
}
🔬 Minimal Reproduction
Here’s the code for the minimal reproduction of the problem: https://stackblitz.com/edit/angular-ivy-p8fd6d?file=src%2Fapp%2Fapp.component.html
Steps to Exemplify the Problem:
add four new elements. The page renders the four <input> fields, the indexes of the elements, and the array of elements behind the <input> fields;
remove an element but the last one;
add a new element.
Current behaviour
The default value of the newly-added element replaces the value of the second last element; the value of the second last element in the app.component.ts’s record array is not changed.
Expected behaviour
It is expected that the addition of a new <input> element should not affect the values of any of the other DOM elements.
🔥 Exception or Error
No exceptions or errors.
🌍 Your Environment
The example is taken from Angular Version 10, but the issue is applicable to all Angular Versions.