fix(forms): updateOn should check if change occurred (#20358)

Fixes #20259.

PR Close #20358
This commit is contained in:
Kara Erickson
2017-11-11 02:54:36 -08:00
committed by Miško Hevery
parent 365712e2f0
commit 69c53c3e03
4 changed files with 253 additions and 5 deletions

View File

@ -484,6 +484,64 @@ export function main() {
sub.unsubscribe();
}));
it('should not fire ngModelChange event on blur unless value has changed', fakeAsync(() => {
const fixture = initTest(NgModelChangesForm);
fixture.componentInstance.name = 'Carson';
fixture.componentInstance.options = {updateOn: 'blur'};
fixture.detectChanges();
tick();
expect(fixture.componentInstance.events)
.toEqual([], 'Expected ngModelChanges not to fire.');
const input = fixture.debugElement.query(By.css('input')).nativeElement;
dispatchEvent(input, 'blur');
fixture.detectChanges();
expect(fixture.componentInstance.events)
.toEqual([], 'Expected ngModelChanges not to fire if value unchanged.');
input.value = 'Carson';
dispatchEvent(input, 'input');
fixture.detectChanges();
tick();
expect(fixture.componentInstance.events)
.toEqual([], 'Expected ngModelChanges not to fire on input.');
dispatchEvent(input, 'blur');
fixture.detectChanges();
expect(fixture.componentInstance.events)
.toEqual(
['fired'], 'Expected ngModelChanges to fire once blurred if value changed.');
dispatchEvent(input, 'blur');
fixture.detectChanges();
expect(fixture.componentInstance.events)
.toEqual(
['fired'],
'Expected ngModelChanges not to fire again on blur unless value changed.');
input.value = 'Bess';
dispatchEvent(input, 'input');
fixture.detectChanges();
tick();
expect(fixture.componentInstance.events)
.toEqual(['fired'], 'Expected ngModelChanges not to fire on input after blur.');
dispatchEvent(input, 'blur');
fixture.detectChanges();
expect(fixture.componentInstance.events)
.toEqual(
['fired', 'fired'],
'Expected ngModelChanges to fire again on blur if value changed.');
}));
});
describe('submit', () => {
@ -764,6 +822,62 @@ export function main() {
sub.unsubscribe();
}));
it('should not fire ngModelChange event on submit unless value has changed',
fakeAsync(() => {
const fixture = initTest(NgModelChangesForm);
fixture.componentInstance.name = 'Carson';
fixture.componentInstance.options = {updateOn: 'submit'};
fixture.detectChanges();
tick();
const formEl = fixture.debugElement.query(By.css('form')).nativeElement;
dispatchEvent(formEl, 'submit');
fixture.detectChanges();
expect(fixture.componentInstance.events)
.toEqual([], 'Expected ngModelChanges not to fire if value unchanged.');
const input = fixture.debugElement.query(By.css('input')).nativeElement;
input.value = 'Carson';
dispatchEvent(input, 'input');
fixture.detectChanges();
tick();
expect(fixture.componentInstance.events)
.toEqual([], 'Expected ngModelChanges not to fire on input.');
dispatchEvent(formEl, 'submit');
fixture.detectChanges();
expect(fixture.componentInstance.events)
.toEqual(
['fired'], 'Expected ngModelChanges to fire once submitted if value changed.');
dispatchEvent(formEl, 'submit');
fixture.detectChanges();
expect(fixture.componentInstance.events)
.toEqual(
['fired'],
'Expected ngModelChanges not to fire again on submit unless value changed.');
input.value = 'Bess';
dispatchEvent(input, 'input');
fixture.detectChanges();
tick();
expect(fixture.componentInstance.events)
.toEqual(['fired'], 'Expected ngModelChanges not to fire on input after submit.');
dispatchEvent(formEl, 'submit');
fixture.detectChanges();
expect(fixture.componentInstance.events)
.toEqual(
['fired', 'fired'],
'Expected ngModelChanges to fire again on submit if value changed.');
}));
});
describe('ngFormOptions', () => {
@ -1670,6 +1784,23 @@ class NgAsyncValidator implements AsyncValidator {
class NgModelAsyncValidation {
}
@Component({
selector: 'ng-model-changes-form',
template: `
<form>
<input name="async" [ngModel]="name" (ngModelChange)="log()"
[ngModelOptions]="options">
</form>
`
})
class NgModelChangesForm {
name: string;
events: string[] = [];
options: any;
log() { this.events.push('fired'); }
}
function sortedClassList(el: HTMLElement) {
const l = getDOM().classList(el);
l.sort();