Skip to content

Commit

Permalink
fix(#841): fix(#841)
Browse files Browse the repository at this point in the history
  • Loading branch information
andriikamaldinov1 committed Aug 15, 2023
1 parent c6a12f6 commit 6428177
Show file tree
Hide file tree
Showing 9 changed files with 397 additions and 10 deletions.
4 changes: 4 additions & 0 deletions projects/ngx-mask-lib/src/lib/ngx-mask-applier.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ export class NgxMaskApplierService {

public apm: IConfig['apm'] = this._config.apm;

public inputTransformFn: IConfig['inputTransformFn'] = this._config.inputTransformFn;

public outputTransformFn: IConfig['outputTransformFn'] = this._config.outputTransformFn;

private _shift: Set<number> = new Set();

public maskExpression = '';
Expand Down
1 change: 1 addition & 0 deletions projects/ngx-mask-lib/src/lib/ngx-mask-expression.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,4 +38,5 @@ export const enum MaskExpression {
DELETE = 'Delete',
ARROW_LEFT = 'ArrowLeft',
ARROW_UP = 'ArrowUp',
CONFIG_FUNC = '(value) => value',
}
4 changes: 4 additions & 0 deletions projects/ngx-mask-lib/src/lib/ngx-mask.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ export interface IConfig {
leadZeroDateTime: boolean;
leadZero: boolean;
triggerOnMaskChange: boolean;
inputTransformFn: (value: string) => string;
outputTransformFn: (value: any) => any;
maskFilled: EventEmitter<void>;
patterns: {
[character: string]: {
Expand Down Expand Up @@ -59,6 +61,8 @@ export const initialConfig: IConfig = {
apm: false,
leadZero: false,
triggerOnMaskChange: false,
inputTransformFn: (value: string) => value,
outputTransformFn: (value: any) => value,
maskFilled: new EventEmitter<void>(),
patterns: {
'0': {
Expand Down
35 changes: 34 additions & 1 deletion projects/ngx-mask-lib/src/lib/ngx-mask.directive.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,10 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida

@Input() public apm: IConfig['apm'] | null = null;

@Input() public inputTransformFn: IConfig['inputTransformFn'] | null = null;

@Input() public outputTransformFn: IConfig['outputTransformFn'] | null = null;

@Output() public maskFilled: IConfig['maskFilled'] = new EventEmitter<void>();

private _maskValue = '';
Expand Down Expand Up @@ -137,6 +141,8 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida
leadZero,
triggerOnMaskChange,
apm,
inputTransformFn,
outputTransformFn,
} = changes;
if (maskExpression) {
if (
Expand Down Expand Up @@ -232,6 +238,12 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida
if (triggerOnMaskChange) {
this._maskService.triggerOnMaskChange = triggerOnMaskChange.currentValue;
}
if (inputTransformFn) {
this._maskService.inputTransformFn = inputTransformFn.currentValue;
}
if (outputTransformFn) {
this._maskService.outputTransformFn = outputTransformFn.currentValue;
}
this._applyMask();
}

Expand Down Expand Up @@ -421,6 +433,17 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida
this._inputValue.slice(position + 1);
}

if (
(this._maskService.inputTransformFn.toString() !== MaskExpression.CONFIG_FUNC ||
this.inputTransformFn) &&
this._code !== MaskExpression.BACKSPACE
) {
el.value = this.inputTransformFn
? this.inputTransformFn(el.value)
: this._maskService.inputTransformFn(el.value);
this._maskService.actualValue = this._inputValue = el.value;
}

this._maskService.applyValueChanges(
position,
this._justPasted,
Expand Down Expand Up @@ -692,7 +715,6 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida
// eslint-disable-next-line no-param-reassign
inputValue = inputValue.value;
}

if (
typeof inputValue === 'number' ||
this._maskValue.startsWith(MaskExpression.SEPARATOR)
Expand Down Expand Up @@ -741,6 +763,14 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida
inputValue = '';
}

if (this.inputTransformFn) {
// eslint-disable-next-line no-param-reassign
inputValue = this.inputTransformFn
? this.inputTransformFn(inputValue)
: this._maskService.inputTransformFn(inputValue);
this._maskService.applyMask(inputValue, this._maskService.maskExpression);
}

this._inputValue = inputValue;
this._setMask();
if (
Expand All @@ -759,6 +789,9 @@ export class NgxMaskDirective implements ControlValueAccessor, OnChanges, Valida
} else {
this._maskService.formElementProperty = ['value', inputValue];
}
// this._inputValue = this.inputTransformFn
// ? this.inputTransformFn(inputValue).toString()
// : inputValue;
this._inputValue = inputValue;
}

Expand Down
20 changes: 12 additions & 8 deletions projects/ngx-mask-lib/src/lib/ngx-mask.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -510,11 +510,13 @@ export class NgxMaskService extends NgxMaskApplierService {
}
if (Array.isArray(this.dropSpecialCharacters)) {
this.onChange(
this._toNumber(
this._checkSymbols(
this._removeMask(
this._removeSuffix(this._removePrefix(inputValue)),
this.dropSpecialCharacters
this.outputTransformFn(
this._toNumber(
this._checkSymbols(
this._removeMask(
this._removeSuffix(this._removePrefix(inputValue)),
this.dropSpecialCharacters
)
)
)
)
Expand All @@ -524,12 +526,14 @@ export class NgxMaskService extends NgxMaskApplierService {
(!this.dropSpecialCharacters && this.prefix === inputValue)
) {
this.onChange(
this._toNumber(
this._checkSymbols(this._removeSuffix(this._removePrefix(inputValue)))
this.outputTransformFn(
this._toNumber(
this._checkSymbols(this._removeSuffix(this._removePrefix(inputValue)))
)
)
);
} else {
this.onChange(this._toNumber(inputValue));
this.onChange(this.outputTransformFn(this._toNumber(inputValue)));
}
}

Expand Down
199 changes: 199 additions & 0 deletions projects/ngx-mask-lib/src/test/inputTransformFn.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,199 @@
import { ComponentFixture, TestBed } from '@angular/core/testing';
import { ReactiveFormsModule } from '@angular/forms';

import { TestMaskComponent } from './utils/test-component.component';
import { equal } from './utils/test-functions.component';
import { NgxMaskDirective } from '../lib/ngx-mask.directive';
import { provideNgxMask } from '../lib/ngx-mask.providers';

describe('Directive: Mask', () => {
let fixture: ComponentFixture<TestMaskComponent>;
let component: TestMaskComponent;

beforeEach(() => {
TestBed.configureTestingModule({
declarations: [TestMaskComponent],
imports: [ReactiveFormsModule, NgxMaskDirective],
providers: [provideNgxMask()],
});
fixture = TestBed.createComponent(TestMaskComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});

it('inputTransformFn should return value toUpperCase', () => {
component.mask = 'S*';
component.inputTransformFn = (value: string): string => value.toUpperCase();

equal('a', 'A', fixture);
equal('an', 'AN', fixture);
equal('and', 'AND', fixture);
equal('andr', 'ANDR', fixture);
equal('andre', 'ANDRE', fixture);
equal('andrey', 'ANDREY', fixture);
});

it('inputTransformFn should return value formValue toUpperCase', () => {
component.mask = 'S*';
component.outputTransformFn = (value: string): string => value.toUpperCase();

equal('a', 'a', fixture);
equal('an', 'an', fixture);
equal('and', 'and', fixture);
equal('andr', 'andr', fixture);
equal('andre', 'andre', fixture);
equal('andrey', 'andrey', fixture);
expect(component.form.value).toBe('ANDREY');
});

it('inputTransformFn should return value formValue toUpperCase but input value to lowerCase', () => {
component.mask = 'S*';
component.outputTransformFn = (value: string): string => value.toUpperCase();
component.inputTransformFn = (value: string): string => value.toLowerCase();

equal('A', 'a', fixture);
equal('AN', 'an', fixture);
equal('AND', 'and', fixture);
equal('ANDR', 'andr', fixture);
equal('ANDRE', 'andre', fixture);
equal('ANDREY', 'andrey', fixture);
expect(component.form.value).toBe('ANDREY');
});

it('separator.2 should replace dot in model', () => {
component.mask = 'separator.2';
component.decimalMarker = '.';
component.outputTransformFn = (value: string): string => {
if (value.includes('.')) {
return value.replace('.', ',');
}
return value;
};

equal('10.2', '10.2', fixture);
expect(component.form.value).toBe('10,2');

equal('109.2', '109.2', fixture);
expect(component.form.value).toBe('109,2');

equal('1000.2', '1 000.2', fixture);
expect(component.form.value).toBe('1000,2');
});

it('separator.3 should toFixed value in model and return Number', () => {
component.mask = 'separator.3';
component.decimalMarker = '.';
component.outputTransformFn = (value: string): number => {
if (value.toString().includes('.')) {
const numberValue = parseFloat(value);
const formattedValue = Number(numberValue.toFixed(2));
return formattedValue;
}
return Number(value);
};

equal('237.356', '237.356', fixture);
expect(component.form.value).toBe(237.36);

equal('11.123', '11.123', fixture);
expect(component.form.value).toBe(11.12);

equal('1234.356', '1 234.356', fixture);
expect(component.form.value).toBe(1234.36);
});

it('mask 000.00 should replace dot in model', () => {
component.mask = '000.00';
component.dropSpecialCharacters = false;
component.outputTransformFn = (value: string): string => {
if (value.includes('.')) {
return value.replace('.', ',');
}
return value;
};

equal('100.22', '100.22', fixture);
expect(component.form.value).toBe('100,22');

equal('12', '12', fixture);
expect(component.form.value).toBe('12');
});

it('mask separator.1 should return number', () => {
component.mask = 'separator.1';
component.decimalMarker = ',';
component.outputTransformFn = (value: string): number => Number(value);

equal('123,2', '123,2', fixture);
expect(component.form.value).toBe(123.2);

equal('10,2', '10,2', fixture);
expect(component.form.value).toBe(10.2);

equal('1,1', '1,1', fixture);
expect(component.form.value).toBe(1.1);

equal('1000,2', '1 000,2', fixture);
expect(component.form.value).toBe(1000.2);
});

it('mask separator.1 should return number decimalMarker dot', () => {
component.mask = 'separator.1';
component.decimalMarker = '.';
component.outputTransformFn = (value: string): number => Number(value);

equal('123.4', '123.4', fixture);
expect(component.form.value).toBe(123.4);

equal('12.2', '12.2', fixture);
expect(component.form.value).toBe(12.2);

equal('1.1', '1.1', fixture);
expect(component.form.value).toBe(1.1);

equal('1000.2', '1 000.2', fixture);
expect(component.form.value).toBe(1000.2);
});

it('mask percent should replace dot in model', () => {
component.mask = 'percent.2';
component.outputTransformFn = (value: string): string => {
if (value.includes('.')) {
return value.replace('.', ',');
}
return value;
};
equal('1.2', '1.2', fixture);
expect(component.form.value).toBe('1,2');

equal('12.2', '12.2', fixture);
expect(component.form.value).toBe('12,2');

equal('34.34', '34.34', fixture);
expect(component.form.value).toBe('34,34');
});

it('mask percent should replace dot in model', () => {
component.mask = 'Hh:m0';
component.showMaskTyped = true;
component.dropSpecialCharacters = false;
component.leadZeroDateTime = true;
component.outputTransformFn = (value: string) => {
const fetch = new Date();
const values = value.split(':');
if (values.length >= 2) {
const hour = Number(values[0]);
const minuts = Number(values[1]);
fetch.setHours(hour);
fetch.setMinutes(minuts);
}
fetch.setSeconds(0);
return fetch.toString();
};

equal('1314', '13:14', fixture);
expect(component.form.value).toBe(
'Tue Aug 15 2023 13:14:00 GMT+0300 (Eastern European Summer Time)'
);
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ import { IConfig } from '../../lib/ngx-mask.config';
[leadZero]="leadZero"
[apm]="apm"
[validation]="validation"
[inputTransformFn]="inputTransformFn || null"
[outputTransformFn]="outputTransformFn || null"
[triggerOnMaskChange]="triggerOnMaskChange" />
`,
})
Expand Down Expand Up @@ -71,5 +73,9 @@ export class TestMaskComponent {

public apm: IConfig['apm'] | undefined;

public inputTransformFn: IConfig['inputTransformFn'] | undefined;

public outputTransformFn: IConfig['outputTransformFn'] | undefined;

public cdr = inject(ChangeDetectorRef);
}
Loading

0 comments on commit 6428177

Please sign in to comment.