Skip to content

Commit e594dc8

Browse files
authored
Merge branch '8.1.x' into slider-label-ie11-8.1.x
2 parents d391fc9 + d0872f1 commit e594dc8

File tree

6 files changed

+294
-36
lines changed

6 files changed

+294
-36
lines changed

projects/igniteui-angular/src/lib/data-operations/filtering-condition.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ export class IgxDateFilteringOperand extends IgxFilteringOperand {
390390
}
391391

392392
protected findValueInSet(target: any, searchVal: Set<any>) {
393+
if (!target) { return false; }
393394
return searchVal.has(new Date(target.getFullYear(), target.getMonth(), target.getDate()).toISOString());
394395
}
395396
}

projects/igniteui-angular/src/lib/directives/input/input.directive.spec.ts

Lines changed: 195 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ describe('IgxInput', () => {
6363
expect(inputElement.classList.contains(TEXTAREA_CSS_CLASS)).toBe(true);
6464
});
6565

66-
it('Should apply focused style.', () => {
66+
it('should apply focused style.', () => {
6767
const fixture = TestBed.createComponent(InputComponent);
6868
fixture.detectChanges();
6969

@@ -83,7 +83,7 @@ describe('IgxInput', () => {
8383
expect(igxInput.focused).toBe(false);
8484
});
8585

86-
it('Should have a placeholder style. Placeholder API.', () => {
86+
it('should have a placeholder style. Placeholder API.', () => {
8787
const fixture = TestBed.createComponent(InputWithPlaceholderComponent);
8888
fixture.detectChanges();
8989

@@ -95,7 +95,7 @@ describe('IgxInput', () => {
9595
expect(igxInput.placeholder).toBe('Test');
9696
});
9797

98-
it('Should have an initial filled style when data bound.', fakeAsync(() => {
98+
it('should have an initial filled style when data bound.', fakeAsync(() => {
9999
const fixture = TestBed.createComponent(InitiallyFilledInputComponent);
100100
fixture.detectChanges();
101101

@@ -127,7 +127,7 @@ describe('IgxInput', () => {
127127
expect(filledDate.classList.contains(INPUT_GROUP_FILLED_CSS_CLASS)).toBe(true);
128128
}));
129129

130-
it('Should have a filled style. Value API.', () => {
130+
it('should have a filled style. Value API.', () => {
131131
const fixture = TestBed.createComponent(FilledInputComponent);
132132
fixture.detectChanges();
133133

@@ -148,7 +148,7 @@ describe('IgxInput', () => {
148148
expect(igxInput.value).toBe('test');
149149
});
150150

151-
it('Should have a disabled style. Disabled API.', () => {
151+
it('should have a disabled style. Disabled API.', () => {
152152
const fixture = TestBed.createComponent(DisabledInputComponent);
153153
fixture.detectChanges();
154154

@@ -167,7 +167,7 @@ describe('IgxInput', () => {
167167
expect(igxInput.disabled).toBe(false);
168168
});
169169

170-
it('Should have a disabled style via binding', () => {
170+
it('should have a disabled style via binding', () => {
171171
const fixture = TestBed.createComponent(DataBoundDisabledInputComponent);
172172
fixture.detectChanges();
173173

@@ -186,15 +186,15 @@ describe('IgxInput', () => {
186186
expect(igxInput.disabled).toBe(true);
187187
});
188188

189-
it('Should style required input correctly.', () => {
189+
it('should style required input correctly.', () => {
190190
const fixture = TestBed.createComponent(RequiredInputComponent);
191191
fixture.detectChanges();
192192

193193
const inputElement = fixture.debugElement.query(By.directive(IgxInputDirective)).nativeElement;
194194
testRequiredValidation(inputElement, fixture);
195195
});
196196

197-
it('Should update style when required input\'s value is set.', () => {
197+
it('should update style when required input\'s value is set.', () => {
198198
const fixture = TestBed.createComponent(RequiredInputComponent);
199199
fixture.detectChanges();
200200

@@ -225,15 +225,15 @@ describe('IgxInput', () => {
225225
expect(igxInput.valid).toBe(IgxInputState.INVALID);
226226
});
227227

228-
it('Should style required input with two-way databinding correctly.', () => {
228+
it('should style required input with two-way databinding correctly.', () => {
229229
const fixture = TestBed.createComponent(RequiredTwoWayDataBoundInputComponent);
230230
fixture.detectChanges();
231231

232232
const inputElement = fixture.debugElement.query(By.directive(IgxInputDirective)).nativeElement;
233233
testRequiredValidation(inputElement, fixture);
234234
});
235235

236-
it('Should work properly with reactive forms validation.', () => {
236+
it('should work properly with reactive forms validation.', () => {
237237
const fixture = TestBed.createComponent(ReactiveFormComponent);
238238
fixture.detectChanges();
239239

@@ -271,7 +271,7 @@ describe('IgxInput', () => {
271271
});
272272
}));
273273

274-
it('When value is changed only via ngModel', fakeAsync(() => {
274+
it('should not draw input as invalid when updated through ngModel and input is pristine and untouched', fakeAsync(() => {
275275
const fix = TestBed.createComponent(RequiredTwoWayDataBoundInputComponent);
276276
fix.detectChanges();
277277

@@ -293,10 +293,10 @@ describe('IgxInput', () => {
293293
fix.detectChanges();
294294
tick();
295295
fix.detectChanges();
296-
expect(inputGroup.nativeElement.classList.contains('igx-input-group--invalid')).toBe(true);
296+
expect(inputGroup.nativeElement.classList.contains('igx-input-group--invalid')).toBe(false);
297297
}));
298298

299-
it('When value is changed via reactive form', fakeAsync(() => {
299+
it('should not draw input as invalid when value is changed via reactive form and input is pristine and untouched', () => {
300300
const fix = TestBed.createComponent(ReactiveFormComponent);
301301
fix.detectChanges();
302302

@@ -305,24 +305,196 @@ describe('IgxInput', () => {
305305

306306
fix.componentInstance.form.patchValue({ str: 'test' });
307307
fix.detectChanges();
308-
tick();
309-
fix.detectChanges();
310308
expect(firstInputGroup.nativeElement.classList.contains('igx-input-group--filled')).toBe(true);
311309

312310
fix.componentInstance.form.patchValue({ str: undefined });
313311
fix.detectChanges();
314-
tick();
315-
fix.detectChanges();
316312
expect(firstInputGroup.nativeElement.classList.contains('igx-input-group--invalid')).toBe(false);
317313

318314
fix.componentInstance.form.patchValue({ str: '' });
319315
fix.detectChanges();
316+
expect(firstInputGroup.nativeElement.classList.contains('igx-input-group--invalid')).toBe(false);
317+
});
318+
319+
it('should correctly update state of input without model when updated trough code', fakeAsync(() => {
320+
const fixture = TestBed.createComponent(RequiredInputComponent);
321+
fixture.detectChanges();
322+
323+
const igxInput = fixture.componentInstance.igxInput;
324+
325+
const inputGroupElement = fixture.debugElement.query(By.css('igx-input-group')).nativeElement;
326+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
327+
expect(igxInput.valid).toBe(IgxInputState.INITIAL);
328+
329+
igxInput.value = 'test';
330+
fixture.detectChanges();
331+
332+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
333+
expect(igxInput.valid).toBe(IgxInputState.VALID);
334+
335+
336+
igxInput.value = '';
337+
fixture.detectChanges();
338+
339+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(true);
340+
expect(igxInput.valid).toBe(IgxInputState.INVALID);
341+
}));
342+
343+
it('should correctly update state of input when updated through ngModel, no user interactions', fakeAsync(() => {
344+
const fixture = TestBed.createComponent(RequiredTwoWayDataBoundInputComponent);
345+
fixture.detectChanges();
346+
347+
const inputGroupElement = fixture.componentInstance.igxInputGroup.element.nativeElement;
348+
const igxInput = fixture.componentInstance.igxInput;
349+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
350+
expect(igxInput.valid).toBe(IgxInputState.INITIAL);
351+
352+
fixture.componentInstance.user.firstName = 'Bobby';
353+
354+
fixture.detectChanges();
320355
tick();
321-
fix.detectChanges();
322-
expect(firstInputGroup.nativeElement.classList.contains('igx-input-group--invalid')).toBe(true);
356+
fixture.detectChanges();
357+
358+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
359+
expect(igxInput.valid).toBe(IgxInputState.INITIAL);
360+
361+
igxInput.value = '';
362+
fixture.detectChanges();
363+
tick();
364+
fixture.detectChanges();
365+
366+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
367+
expect(igxInput.valid).toBe(IgxInputState.INITIAL);
368+
369+
igxInput.value = undefined;
370+
fixture.detectChanges();
371+
tick();
372+
fixture.detectChanges();
373+
374+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
375+
expect(igxInput.valid).toBe(IgxInputState.INITIAL);
376+
}));
377+
378+
it('should correctly update state of input when value is changed via reactive, no user interactions', fakeAsync(() => {
379+
const fixture = TestBed.createComponent(ReactiveFormComponent);
380+
fixture.detectChanges();
381+
382+
const igxInputGroups = fixture.debugElement.queryAll(By.css('igx-input-group'));
383+
const inputGroupElement = igxInputGroups[0].nativeElement;
384+
const igxInput = fixture.componentInstance.strIgxInput;
385+
386+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
387+
expect(igxInput.valid).toBe(IgxInputState.INITIAL);
388+
389+
fixture.componentInstance.form.patchValue({ str: 'Bobby' });
390+
fixture.detectChanges();
391+
392+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
393+
expect(igxInput.valid).toBe(IgxInputState.INITIAL);
394+
395+
fixture.componentInstance.form.patchValue({ str: '' });
396+
fixture.detectChanges();
397+
398+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
399+
expect(igxInput.valid).toBe(IgxInputState.INITIAL);
400+
401+
fixture.componentInstance.form.patchValue({ str: undefined });
402+
fixture.detectChanges();
403+
404+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
405+
expect(igxInput.valid).toBe(IgxInputState.INITIAL);
406+
407+
fixture.componentInstance.form.reset();
408+
fixture.detectChanges();
409+
410+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
411+
expect(igxInput.valid).toBe(IgxInputState.INITIAL);
323412
}));
324413

325-
it('Should style input when required is toggled dynamically.', () => {
414+
it('should correctly update state of input when updated through ngModel, with user interactions', fakeAsync(() => {
415+
const fixture = TestBed.createComponent(RequiredTwoWayDataBoundInputComponent);
416+
fixture.detectChanges();
417+
418+
const inputGroupElement = fixture.componentInstance.igxInputGroup.element.nativeElement;
419+
const igxInput = fixture.componentInstance.igxInput;
420+
const inputElement = igxInput.nativeElement;
421+
422+
dispatchInputEvent('focus', inputElement, fixture);
423+
dispatchInputEvent('blur', inputElement, fixture);
424+
425+
tick();
426+
fixture.detectChanges();
427+
428+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(true);
429+
expect(igxInput.valid).toBe(IgxInputState.INVALID);
430+
431+
fixture.componentInstance.user.firstName = 'Bobby';
432+
433+
fixture.detectChanges();
434+
tick();
435+
fixture.detectChanges();
436+
437+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
438+
expect(igxInput.valid).toBe(IgxInputState.INITIAL);
439+
440+
fixture.componentInstance.user.firstName = '';
441+
fixture.detectChanges();
442+
tick();
443+
fixture.detectChanges();
444+
445+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(true);
446+
expect(igxInput.valid).toBe(IgxInputState.INVALID);
447+
448+
fixture.componentInstance.user.firstName = undefined;
449+
fixture.detectChanges();
450+
tick();
451+
fixture.detectChanges();
452+
453+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(true);
454+
expect(igxInput.valid).toBe(IgxInputState.INVALID);
455+
}));
456+
457+
it('should correctly update state of input when value is changed via reactive, with user interactions', fakeAsync(() => {
458+
const fixture = TestBed.createComponent(ReactiveFormComponent);
459+
fixture.detectChanges();
460+
461+
const igxInputGroups = fixture.debugElement.queryAll(By.css('igx-input-group'));
462+
const inputGroupElement = igxInputGroups[0].nativeElement;
463+
const igxInput = fixture.componentInstance.strIgxInput;
464+
const input = igxInput.nativeElement;
465+
466+
dispatchInputEvent('focus', input, fixture);
467+
dispatchInputEvent('blur', input, fixture);
468+
469+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(true);
470+
expect(igxInput.valid).toBe(IgxInputState.INVALID);
471+
472+
fixture.componentInstance.form.patchValue({ str: 'Bobby' });
473+
fixture.detectChanges();
474+
475+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
476+
expect(igxInput.valid).toBe(IgxInputState.INITIAL);
477+
478+
fixture.componentInstance.form.patchValue({ str: '' });
479+
fixture.detectChanges();
480+
481+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(true);
482+
expect(igxInput.valid).toBe(IgxInputState.INVALID);
483+
484+
fixture.componentInstance.form.patchValue({ str: undefined });
485+
fixture.detectChanges();
486+
487+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(true);
488+
expect(igxInput.valid).toBe(IgxInputState.INVALID);
489+
490+
fixture.componentInstance.form.reset();
491+
fixture.detectChanges();
492+
493+
expect(inputGroupElement.classList.contains(INPUT_GROUP_INVALID_CSS_CLASS)).toBe(false);
494+
expect(igxInput.valid).toBe(IgxInputState.INITIAL);
495+
}));
496+
497+
it('should style input when required is toggled dynamically.', () => {
326498
const fixture = TestBed.createComponent(ToggleRequiredWithNgModelInputComponent);
327499
fixture.detectChanges();
328500

@@ -377,7 +549,7 @@ describe('IgxInput', () => {
377549
expect(inputGroup.element.nativeElement.classList.contains(INPUT_GROUP_VALID_CSS_CLASS)).toBe(false);
378550
});
379551

380-
it('Should style input with ngModel when required is toggled dynamically.', () => {
552+
it('should style input with ngModel when required is toggled dynamically.', () => {
381553
const fixture = TestBed.createComponent(ToggleRequiredWithNgModelInputComponent);
382554
fixture.detectChanges();
383555

@@ -620,6 +792,8 @@ class DataBoundDisabledInputComponent {
620792
</form>`
621793
})
622794
class ReactiveFormComponent {
795+
@ViewChild(IgxInputDirective, { static: true }) public strIgxInput: IgxInputDirective;
796+
623797
form = this.fb.group({
624798
str: ['', Validators.required],
625799
textarea: ['', Validators.required],

projects/igniteui-angular/src/lib/directives/input/input.directive.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -248,17 +248,18 @@ export class IgxInputDirective implements AfterViewInit, OnDestroy {
248248
protected onStatusChanged() {
249249
if (this.ngControl.control.validator || this.ngControl.control.asyncValidator) {
250250
if (this.ngControl.control.touched || this.ngControl.control.dirty) {
251+
// TODO: check the logic when control is touched or dirty
251252
if (this.inputGroup.isFocused) {
252253
// the user is still typing in the control
253254
this._valid = this.ngControl.valid ? IgxInputState.VALID : IgxInputState.INVALID;
254255
} else {
255-
// the user had touched the control previosly but now the value is changing due to changes in the form
256+
// the user had touched the control previously but now the value is changing due to changes in the form
256257
this._valid = this.ngControl.valid ? IgxInputState.INITIAL : IgxInputState.INVALID;
257258
}
258-
} else if (this._valid !== IgxInputState.INITIAL) {
259-
this._valid = this.ngControl.valid ? IgxInputState.INITIAL : IgxInputState.INVALID;
260-
} else if (this._valid === IgxInputState.INITIAL && this.ngControl.value !== undefined && this.ngControl.invalid) {
261-
this._valid = IgxInputState.INVALID;
259+
} else {
260+
// if control is untouched and pristine its state is initial. This is when user did not interact
261+
// with the input or when form/control is reset
262+
this._valid = IgxInputState.INITIAL;
262263
}
263264
}
264265
}

projects/igniteui-angular/src/lib/grids/filtering/grid-filtering.service.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ import { IgxDatePipeComponent } from '../grid.common';
1212
import { IgxColumnComponent } from '../column.component';
1313
import { IFilteringOperation } from '../../data-operations/filtering-condition';
1414
import { GridBaseAPIService } from '../api.service';
15+
import { IColumnVisibilityChangedEventArgs } from '../grid';
1516

1617
const FILTERING_ICONS_FONT_SET = 'filtering-icons';
1718

@@ -113,6 +114,13 @@ export class IgxFilteringService implements OnDestroy {
113114
filterCell.updateFilterCellArea();
114115
});
115116
});
117+
118+
this.grid.onColumnVisibilityChanged.pipe(takeUntil(this.destroy$)).subscribe((eventArgs: IColumnVisibilityChangedEventArgs) => {
119+
if (this.grid.filteringRow && this.grid.filteringRow.column === eventArgs.column ) {
120+
this.grid.filteringRow.close();
121+
122+
}
123+
});
116124
}
117125
}
118126

0 commit comments

Comments
 (0)