Skip to content

Commit 64be7ec

Browse files
authored
Merge branch 'master' into sstoychev/remove-dblclick-master
2 parents bb01fdd + 79f4428 commit 64be7ec

File tree

5 files changed

+100
-32
lines changed

5 files changed

+100
-32
lines changed

projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.spec.ts

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { IgxDateTimeEditorDirective, IgxDateTimeEditorModule } from './date-time-editor.directive';
22
import { DatePart } from './date-time-editor.common';
3-
import { DOCUMENT } from '@angular/common';
3+
import { DOCUMENT, formatDate } from '@angular/common';
44
import { Component, ViewChild, DebugElement, EventEmitter, Output, SimpleChange, SimpleChanges } from '@angular/core';
55
import { fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
66
import { FormsModule, FormGroup, FormBuilder, ReactiveFormsModule, Validators, NgControl } from '@angular/forms';
@@ -15,7 +15,7 @@ describe('IgxDateTimeEditor', () => {
1515
let dateTimeEditor: IgxDateTimeEditorDirective;
1616
describe('Unit tests', () => {
1717
const maskParsingService = jasmine.createSpyObj('MaskParsingService',
18-
['parseMask', 'restoreValueFromMask', 'parseMaskValue', 'applyMask']);
18+
['parseMask', 'restoreValueFromMask', 'parseMaskValue', 'applyMask', 'parseValueFromMask']);
1919
const renderer2 = jasmine.createSpyObj('Renderer2', ['setAttribute']);
2020
const locale = 'en';
2121
const _ngModel = {
@@ -647,11 +647,7 @@ describe('IgxDateTimeEditor', () => {
647647
inputElement.triggerEventHandler('blur', { target: inputElement.nativeElement });
648648
fixture.detectChanges();
649649
date = new Date(2010, 10, 10, 2, 0, 0);
650-
const longTimeOptions = { hour: 'numeric', minute: 'numeric', second: 'numeric', hour12: true };
651-
result = ControlsFunction.formatDate(date, longTimeOptions);
652-
const offset = date.getTimezoneOffset();
653-
const tz = (offset > 0 ? '-' : '+') + (Math.abs(offset) / 60);
654-
result = `${result} GMT${tz}`;
650+
result = formatDate(date, 'longTime', 'en-US');
655651
expect(inputElement.nativeElement.value).toEqual(result);
656652
});
657653
it('should be able to apply custom display format.', fakeAsync(() => {

projects/igniteui-angular/src/lib/directives/date-time-editor/date-time-editor.directive.ts

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -254,21 +254,21 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
254254
}
255255
}
256256

257-
private get hasDateParts() {
257+
private get hasDateParts(): boolean {
258258
return this._inputDateParts.some(
259259
p => p.type === DatePart.Date
260260
|| p.type === DatePart.Month
261261
|| p.type === DatePart.Year);
262262
}
263263

264-
private get hasTimeParts() {
264+
private get hasTimeParts(): boolean {
265265
return this._inputDateParts.some(
266266
p => p.type === DatePart.Hours
267267
|| p.type === DatePart.Minutes
268268
|| p.type === DatePart.Seconds);
269269
}
270270

271-
private get dateValue() {
271+
private get dateValue(): Date {
272272
return this._dateValue;
273273
}
274274

@@ -285,7 +285,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
285285
}
286286

287287
@HostListener('wheel', ['$event'])
288-
public onWheel(event: WheelEvent) {
288+
public onWheel(event: WheelEvent): void {
289289
if (!this._isFocused) {
290290
return;
291291
}
@@ -305,7 +305,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
305305
}
306306

307307
/** @hidden @internal */
308-
public ngOnChanges(changes: SimpleChanges) {
308+
public ngOnChanges(changes: SimpleChanges): void {
309309
if (changes['locale'] && !changes['locale'].firstChange) {
310310
this.updateDefaultFormat();
311311
if (!this._inputFormat) {
@@ -406,7 +406,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
406406
public setDisabledState?(_isDisabled: boolean): void { }
407407

408408
/** @hidden @internal */
409-
public onInputChanged(isComposing: boolean) {
409+
public onInputChanged(isComposing: boolean): void {
410410
super.onInputChanged(isComposing);
411411
if (this.inputIsComplete()) {
412412
const parsedDate = this.parseDate(this.inputValue);
@@ -479,6 +479,10 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
479479
super.onBlur(value);
480480
}
481481

482+
// the date editor sets its own inputFormat as its placeholder if none is provided
483+
/** @hidden */
484+
protected setPlaceholder(_value: string): void { }
485+
482486
private updateDefaultFormat(): void {
483487
this._defaultInputFormat = DateTimeUtil.getDefaultInputFormat(this.locale);
484488
}
@@ -508,7 +512,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
508512
}
509513
}
510514

511-
private setMask(inputFormat: string) {
515+
private setMask(inputFormat: string): void {
512516
const oldFormat = this._inputDateParts?.map(p => p.format).join('');
513517
this._inputDateParts = DateTimeUtil.parseDateTimeFormat(inputFormat);
514518
inputFormat = this._inputDateParts.map(p => p.format).join('');
@@ -599,7 +603,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
599603
return newDate;
600604
}
601605

602-
private trySpinValue(datePart: DatePart, delta?: number, negative = false) {
606+
private trySpinValue(datePart: DatePart, delta?: number, negative = false): Date {
603607
if (!delta) {
604608
// default to 1 if a delta is set to 0 or any other falsy value
605609
delta = this.datePartDeltas[datePart] || 1;
@@ -608,7 +612,7 @@ export class IgxDateTimeEditorDirective extends IgxMaskDirective implements OnCh
608612
return this.spinValue(datePart, spinValue) || new Date();
609613
}
610614

611-
private setDateValue(value: Date | string) {
615+
private setDateValue(value: Date | string): void {
612616
this._dateValue = DateTimeUtil.isValidDate(value)
613617
? value
614618
: DateTimeUtil.parseIsoDate(value);

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

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Component, Input, ViewChild, ElementRef, Pipe, PipeTransform } from '@angular/core';
1+
import { Component, Input, ViewChild, ElementRef, Pipe, PipeTransform, Renderer2 } from '@angular/core';
22
import { fakeAsync, TestBed, tick, waitForAsync } from '@angular/core/testing';
33
import { FormsModule } from '@angular/forms';
44
import { IgxInputGroupModule } from '../../input-group/input-group.component';
@@ -238,7 +238,7 @@ describe('igxMask', () => {
238238
const comp = fixture.componentInstance;
239239
const input = comp.input;
240240

241-
expect(input.nativeElement.value).toEqual('3456');
241+
expect(input.nativeElement.value).toEqual('3456____');
242242

243243
input.nativeElement.dispatchEvent(new Event('focus'));
244244
tick();
@@ -411,10 +411,45 @@ describe('igxMask', () => {
411411
expect((maskDirective as any).showMask).toHaveBeenCalledTimes(0);
412412
expect((maskDirective as any).inputValue).toEqual('');
413413
}));
414+
415+
it('should be able to update the mask dynamically', fakeAsync(() => {
416+
const fixture = TestBed.createComponent(DefMaskComponent);
417+
fixture.detectChanges();
418+
const input = fixture.componentInstance.input;
419+
420+
expect(input.nativeElement.value).toEqual('');
421+
expect(input.nativeElement.placeholder).toEqual('CCCCCCCCCC');
422+
423+
fixture.componentInstance.mask = '00-00-00';
424+
fixture.detectChanges();
425+
expect(fixture.componentInstance.maskDirective.mask).toEqual('00-00-00');
426+
expect(input.nativeElement.placeholder).toEqual('00-00-00');
427+
428+
fixture.componentInstance.mask = '0';
429+
fixture.detectChanges();
430+
expect(fixture.componentInstance.maskDirective.mask).toEqual('0');
431+
expect(input.nativeElement.placeholder).toEqual('0');
432+
433+
fixture.componentInstance.mask = undefined;
434+
fixture.detectChanges();
435+
expect(fixture.componentInstance.maskDirective.mask).toEqual('CCCCCCCCCC');
436+
expect(input.nativeElement.placeholder).toEqual('CCCCCCCCCC');
437+
438+
fixture.componentInstance.mask = '';
439+
fixture.detectChanges();
440+
expect(fixture.componentInstance.maskDirective.mask).toEqual('CCCCCCCCCC');
441+
expect(input.nativeElement.placeholder).toEqual('CCCCCCCCCC');
442+
443+
fixture.componentInstance.mask = '##.##';
444+
fixture.detectChanges();
445+
expect(fixture.componentInstance.maskDirective.mask).toEqual('##.##');
446+
expect(input.nativeElement.placeholder).toEqual('##.##');
447+
}));
414448
});
415449

416450
describe('igxMaskDirective ControlValueAccessor Unit', () => {
417451
let mask: IgxMaskDirective;
452+
let renderer2: Renderer2;
418453
it('Should correctly implement interface methods', () => {
419454
const mockNgControl = jasmine.createSpyObj('NgControl', ['registerOnChangeCb', 'registerOnTouchedCb']);
420455
const platformMock = {
@@ -436,7 +471,8 @@ describe('igxMaskDirective ControlValueAccessor Unit', () => {
436471
const format = 'CCCCCCCC';
437472

438473
// init
439-
mask = new IgxMaskDirective({ nativeElement: {} } as any, mockParser, null, platformMock as any);
474+
renderer2 = jasmine.createSpyObj('Renderer2', ['setAttribute']);
475+
mask = new IgxMaskDirective({ nativeElement: {} } as any, mockParser, renderer2, platformMock as any);
440476
mask.mask = format;
441477
mask.registerOnChange(mockNgControl.registerOnChangeCb);
442478
mask.registerOnTouched(mockNgControl.registerOnTouchedCb);
@@ -475,9 +511,12 @@ describe('igxMaskDirective ControlValueAccessor Unit', () => {
475511
<input #input type="text" igxInput [(ngModel)]="value" [igxMask]="mask"/>
476512
</igx-input-group>` })
477513
class DefMaskComponent {
478-
479514
@ViewChild('input', { static: true })
480515
public input: ElementRef;
516+
517+
@ViewChild(IgxMaskDirective)
518+
public maskDirective: IgxMaskDirective;
519+
481520
public mask;
482521
public value;
483522
}

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

Lines changed: 40 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,19 @@ export class IgxMaskDirective implements OnInit, AfterViewChecked, ControlValueA
2323
* ```
2424
*/
2525
@Input('igxMask')
26-
public mask: string;
26+
public get mask(): string {
27+
return this._mask || this.defaultMask;
28+
}
29+
30+
public set mask(val: string) {
31+
// B.P. 9th June 2021 #7490
32+
if (val !== this._mask) {
33+
const cleanInputValue = this.maskParser.parseValueFromMask(this.inputValue, this.maskOptions);
34+
this.setPlaceholder(val);
35+
this._mask = val;
36+
this.updateInputValue(cleanInputValue);
37+
}
38+
}
2739

2840
/**
2941
* Sets the character representing a fillable spot in the input mask.
@@ -98,13 +110,13 @@ export class IgxMaskDirective implements OnInit, AfterViewChecked, ControlValueA
98110
}
99111

100112
/** @hidden @internal */
101-
protected set inputValue(val) {
113+
protected set inputValue(val: string) {
102114
this.nativeElement.value = val;
103115
}
104116

105117
/** @hidden */
106118
protected get maskOptions(): MaskOptions {
107-
const format = this.mask || 'CCCCCCCCCC';
119+
const format = this.mask || this.defaultMask;
108120
const promptChar = this.promptChar && this.promptChar.substring(0, 1);
109121
return { format, promptChar };
110122
}
@@ -135,13 +147,16 @@ export class IgxMaskDirective implements OnInit, AfterViewChecked, ControlValueA
135147
private _end = 0;
136148
private _start = 0;
137149
private _key: string;
150+
private _mask: string;
138151
private _oldText = '';
139152
private _dataValue = '';
140153
private _focused = false;
141154
private _droppedData: string;
142155
private _hasDropAction: boolean;
143156
private _stopPropagation: boolean;
144157

158+
private readonly defaultMask = 'CCCCCCCCCC';
159+
145160
private _onTouchedCallback: () => void = noop;
146161
private _onChangeCallback: (_: any) => void = noop;
147162

@@ -239,7 +254,7 @@ export class IgxMaskDirective implements OnInit, AfterViewChecked, ControlValueA
239254
return;
240255
}
241256
this._focused = true;
242-
this.showMask(this._dataValue);
257+
this.showMask(this.inputValue);
243258
}
244259

245260
/** @hidden */
@@ -275,9 +290,7 @@ export class IgxMaskDirective implements OnInit, AfterViewChecked, ControlValueA
275290

276291
/** @hidden */
277292
public ngOnInit(): void {
278-
if (!this.nativeElement.placeholder) {
279-
this.renderer.setAttribute(this.nativeElement, 'placeholder', this.maskOptions.format);
280-
}
293+
this.setPlaceholder(this.maskOptions.format);
281294
}
282295

283296
/**
@@ -316,15 +329,15 @@ export class IgxMaskDirective implements OnInit, AfterViewChecked, ControlValueA
316329
}
317330

318331
/** @hidden */
319-
protected showMask(value: string) {
332+
protected showMask(value: string): void {
320333
if (this.focusedValuePipe) {
321334
if (this.platform.isIE) {
322335
this._stopPropagation = true;
323336
}
324337
// TODO(D.P.): focusedValuePipe should be deprecated or force-checked to match mask format
325338
this.inputValue = this.focusedValuePipe.transform(value);
326339
} else {
327-
this.inputValue = this.maskParser.applyMask(this.inputValue, this.maskOptions);
340+
this.inputValue = this.maskParser.applyMask(value, this.maskOptions);
328341
}
329342

330343
this._oldText = this.inputValue;
@@ -336,15 +349,31 @@ export class IgxMaskDirective implements OnInit, AfterViewChecked, ControlValueA
336349
}
337350

338351
/** @hidden */
339-
protected afterInput() {
352+
protected afterInput(): void {
340353
this._oldText = this.inputValue;
341354
this._hasDropAction = false;
342355
this._start = 0;
343356
this._end = 0;
344357
this._key = null;
345358
}
346359

347-
private showDisplayValue(value: string) {
360+
/** @hidden */
361+
protected setPlaceholder(value: string): void {
362+
const placeholder = this.nativeElement.placeholder;
363+
if (!placeholder || placeholder === this.mask) {
364+
this.renderer.setAttribute(this.nativeElement, 'placeholder', value || this.defaultMask);
365+
}
366+
}
367+
368+
private updateInputValue(value: string) {
369+
if (this._focused) {
370+
this.showMask(value);
371+
} else if (!this.displayValuePipe) {
372+
this.inputValue = this.inputValue ? this.maskParser.applyMask(value, this.maskOptions) : '';
373+
}
374+
}
375+
376+
private showDisplayValue(value: string): void {
348377
if (this.displayValuePipe) {
349378
this.inputValue = this.displayValuePipe.transform(value);
350379
} else if (value === this.maskParser.applyMask(null, this.maskOptions)) {

projects/igniteui-angular/src/lib/grids/cell.component.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -988,7 +988,7 @@ export class IgxGridCellComponent implements OnInit, OnChanges, OnDestroy {
988988
this.grid.cdr.detectChanges();
989989
}
990990

991-
if (editableArgs.cancel) {
991+
if (editableArgs && editableArgs.cancel) {
992992
return true;
993993
}
994994

0 commit comments

Comments
 (0)