Skip to content

Commit

Permalink
fix(forms): Don't send updates for same value
Browse files Browse the repository at this point in the history
In case an input event sends the same value to our forms, we will discard the update and consider the input hasn't change. This will prevent having duplicate values on the valueChanges event.

Fixes angular#43228
  • Loading branch information
JeanMeche committed May 11, 2024
1 parent 85ac2de commit adb160f
Show file tree
Hide file tree
Showing 3 changed files with 13 additions and 10 deletions.
7 changes: 5 additions & 2 deletions packages/forms/src/directives/shared.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,8 +249,11 @@ export function cleanUpValidators(

function setUpViewChangePipeline(control: FormControl, dir: NgControl): void {
dir.valueAccessor!.registerOnChange((newValue: any) => {
control._pendingValue = newValue;
control._pendingChange = true;
if (newValue !== control.value) {
control._pendingValue = newValue;
control._pendingChange = true;
}

control._pendingDirty = true;

if (control.updateOn === 'change') updateControl(control, dir);
Expand Down
13 changes: 6 additions & 7 deletions packages/forms/test/template_integration_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -721,7 +721,7 @@ describe('template-driven forms integration tests', () => {
.withContext('Expected ngModelChanges not to fire if value unchanged.')
.toEqual([]);

input.value = 'Carson';
input.value = 'Not Carson !'; // changes the existing input value
dispatchEvent(input, 'input');
fixture.detectChanges();
tick();
Expand Down Expand Up @@ -1077,10 +1077,9 @@ describe('template-driven forms integration tests', () => {
.toEqual([]);

const input = fixture.debugElement.query(By.css('input')).nativeElement;
input.value = 'Carson';
input.value = 'Not Carson !'; // Changing the existing input value
dispatchEvent(input, 'input');
fixture.detectChanges();
tick();

expect(fixture.componentInstance.events)
.withContext('Expected ngModelChanges not to fire on input.')
Expand All @@ -1095,11 +1094,11 @@ describe('template-driven forms integration tests', () => {

dispatchEvent(formEl, 'submit');
fixture.detectChanges();
tick();

expect(fixture.componentInstance.events).toEqual(
['fired'],
'Expected ngModelChanges not to fire again on submit unless value changed.',
);
expect(fixture.componentInstance.events)
.withContext('Expected ngModelChanges not to fire again on submit unless value changed.')
.toEqual(['fired']);

input.value = 'Bess';
dispatchEvent(input, 'input');
Expand Down
3 changes: 2 additions & 1 deletion packages/forms/test/value_accessor_integration_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -377,6 +377,7 @@ describe('value accessors', () => {
comp.cities = [{'name': 'SF'}, {'name': 'NYC'}];
comp.selectedCity = null;
fixture.detectChanges();
tick();

const select = fixture.debugElement.query(By.css('select'));

Expand Down Expand Up @@ -1429,7 +1430,7 @@ class NgModelSelectForm {
@Component({
selector: 'ng-model-select-null-form',
template: `
<select [(ngModel)]="selectedCity">
<select [(ngModel)]="selectedCity" #model="ngModel">
<option *ngFor="let c of cities" [ngValue]="c"> {{c.name}} </option>
<option [ngValue]="null">Unspecified</option>
</select>
Expand Down

0 comments on commit adb160f

Please sign in to comment.