Skip to content

Commit 66a6cb7

Browse files
SaucistopheThegrep01
authored andcommitted
Allow placeholder customization (JsDaddy#595)
1 parent 2bae26a commit 66a6cb7

File tree

9 files changed

+126
-8
lines changed

9 files changed

+126
-8
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,16 @@ Model value: 789-874.98
182182
<input mask="(000) 000-0000" prefix="+7" [showMaskTyped] = "true">
183183
```
184184
185+
### placeHolderCharacter (string)
186+
187+
If the `showMaskTyped` parameter is enabled, this setting customizes the character used as placeholder. Default value is '_'.
188+
189+
##### Usage
190+
191+
```html
192+
<input mask="(000) 000-0000" prefix="+7" [showMaskTyped] = "true" placeHolderCharacter="*">
193+
```
194+
185195
### clearIfNotMatch (boolean)
186196
You can choose clear the input if the input value **not match** the mask, default value false
187197

package-lock.json

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/app/app.component.html

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -330,6 +330,45 @@ <h1 class="title">
330330
</div>
331331
</div>
332332
</div>
333+
<div class="container">
334+
<div class="row">
335+
<div class="col-12">
336+
<div class="mat-card-wr">
337+
<mat-card>
338+
<mat-card-header>
339+
<mat-card-title>Phone number</mat-card-title>
340+
<mat-card-subtitle>
341+
You can add 'placeHolderCharacter' property to changed the placeholder character used when displaying the mask.
342+
</mat-card-subtitle>
343+
</mat-card-header>
344+
<mat-card-content>
345+
<div class="flex-row">
346+
<div class="flex-cell-padding">
347+
<mat-form-field>
348+
<input
349+
matInput
350+
placeholder="Phone number"
351+
mask="(000) 000-0000"
352+
[formControl]="form1"
353+
prefix="+5"
354+
[(ngModel)]="showMaskModel"
355+
[showMaskTyped]="true"
356+
placeHolderCharacter="*"
357+
/>
358+
<mat-hint><b>Mask: </b>+5 (000) 000 0000</mat-hint>
359+
</mat-form-field>
360+
</div>
361+
<div class="flex-cell">
362+
<p><b>FormControl:</b> {{ form1.value ? form1.value : 'Empty' }}</p>
363+
<p><b>NgModel:</b> {{ showMaskModel ? showMaskModel : 'Empty' }}</p>
364+
</div>
365+
</div>
366+
</mat-card-content>
367+
</mat-card>
368+
</div>
369+
</div>
370+
</div>
371+
</div>
333372
<div class="container">
334373
<div class="row">
335374
<div class="col-12">

src/app/ngx-mask/config.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export interface IConfig {
88
clearIfNotMatch: boolean;
99
showTemplate: boolean;
1010
showMaskTyped: boolean;
11+
placeHolderCharacter: string;
1112
shownMaskExpression: string;
1213
dropSpecialCharacters: boolean | string[];
1314
specialCharacters: string[];
@@ -36,6 +37,7 @@ export const initialConfig: IConfig = {
3637
clearIfNotMatch: false,
3738
showTemplate: false,
3839
showMaskTyped: false,
40+
placeHolderCharacter: '_',
3941
dropSpecialCharacters: true,
4042
hiddenInput: undefined,
4143
shownMaskExpression: '',

src/app/ngx-mask/mask-applier.service.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export class MaskApplierService {
1919
public customPattern!: IConfig['patterns'];
2020
public ipError?: boolean;
2121
public showMaskTyped!: IConfig['showMaskTyped'];
22+
public placeHolderCharacter!: IConfig['placeHolderCharacter'];
2223
public validation: IConfig['validation'];
2324
public separatorLimit: IConfig['separatorLimit'];
2425

@@ -36,6 +37,7 @@ export class MaskApplierService {
3637
this.decimalMarker = this._config.decimalMarker;
3738
this.hiddenInput = this._config.hiddenInput;
3839
this.showMaskTyped = this._config.showMaskTyped;
40+
this.placeHolderCharacter = this._config.placeHolderCharacter;
3941
this.validation = this._config.validation;
4042
this.separatorLimit = this._config.separatorLimit;
4143
}
@@ -326,7 +328,7 @@ export class MaskApplierService {
326328
} else if (
327329
this.showMaskTyped &&
328330
this.maskSpecialCharacters.indexOf(inputSymbol) < 0 &&
329-
inputSymbol !== '_'
331+
inputSymbol !== this.placeHolderCharacter
330332
) {
331333
stepBack = true;
332334
}

src/app/ngx-mask/mask.directive.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ export class MaskDirective implements ControlValueAccessor, OnChanges {
3232
@Input() public dropSpecialCharacters: IConfig['dropSpecialCharacters'] | null = null;
3333
@Input() public hiddenInput: IConfig['hiddenInput'] | null = null;
3434
@Input() public showMaskTyped: IConfig['showMaskTyped'] | null = null;
35+
@Input() public placeHolderCharacter: IConfig['placeHolderCharacter'] | null = null;
3536
@Input() public shownMaskExpression: IConfig['shownMaskExpression'] | null = null;
3637
@Input() public showTemplate: IConfig['showTemplate'] | null = null;
3738
@Input() public clearIfNotMatch: IConfig['clearIfNotMatch'] | null = null;
@@ -56,7 +57,7 @@ export class MaskDirective implements ControlValueAccessor, OnChanges {
5657
public onTouch = () => {};
5758

5859
public ngOnChanges(changes: SimpleChanges): void {
59-
// tslint:disable-next-line:max-line-length
60+
// tslint:disable-next-line:max-line-length: cyclomatic-complexity
6061
const {
6162
maskExpression,
6263
specialCharacters,
@@ -68,6 +69,7 @@ export class MaskDirective implements ControlValueAccessor, OnChanges {
6869
dropSpecialCharacters,
6970
hiddenInput,
7071
showMaskTyped,
72+
placeHolderCharacter,
7173
shownMaskExpression,
7274
showTemplate,
7375
clearIfNotMatch,
@@ -108,6 +110,9 @@ export class MaskDirective implements ControlValueAccessor, OnChanges {
108110
if (showMaskTyped) {
109111
this._maskService.showMaskTyped = showMaskTyped.currentValue;
110112
}
113+
if (placeHolderCharacter) {
114+
this._maskService.placeHolderCharacter = placeHolderCharacter.currentValue;
115+
}
111116
if (shownMaskExpression) {
112117
this._maskService.shownMaskExpression = shownMaskExpression.currentValue;
113118
}

src/app/ngx-mask/mask.service.ts

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ export class MaskService extends MaskApplierService {
99
public maskExpression: string = '';
1010
public isNumberValue: boolean = false;
1111
public showMaskTyped: boolean = false;
12+
public placeHolderCharacter: string = '_';
1213
public maskIsShown: string = '';
1314
public selStart: number | null = null;
1415
public selEnd: number | null = null;
@@ -165,7 +166,7 @@ export class MaskService extends MaskApplierService {
165166
if (inputVal) {
166167
return this._checkForIp(inputVal);
167168
}
168-
return this.maskExpression.replace(/\w/g, '_');
169+
return this.maskExpression.replace(/\w/g, this.placeHolderCharacter);
169170
}
170171
return '';
171172
}
@@ -192,7 +193,7 @@ export class MaskService extends MaskApplierService {
192193

193194
private _checkForIp(inputVal: string): string {
194195
if (inputVal === '#') {
195-
return '_._._._';
196+
return `${this.placeHolderCharacter}.${this.placeHolderCharacter}.${this.placeHolderCharacter}.${this.placeHolderCharacter}`;
196197
}
197198
const arr: string[] = [];
198199
for (let i: number = 0; i < inputVal.length; i++) {
@@ -201,13 +202,13 @@ export class MaskService extends MaskApplierService {
201202
}
202203
}
203204
if (arr.length <= 3) {
204-
return '_._._';
205+
return `${this.placeHolderCharacter}.${this.placeHolderCharacter}.${this.placeHolderCharacter}`;
205206
}
206207
if (arr.length > 3 && arr.length <= 6) {
207-
return '_._';
208+
return `${this.placeHolderCharacter}.${this.placeHolderCharacter}`;
208209
}
209210
if (arr.length > 6 && arr.length <= 9) {
210-
return '_';
211+
return `${this.placeHolderCharacter}`;
211212
}
212213
if (arr.length > 9 && arr.length <= 12) {
213214
return '';
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import { ComponentFixture, TestBed } from '@angular/core/testing';
2+
import { NgxMaskModule } from '../ngx-mask.module';
3+
import { ReactiveFormsModule } from '@angular/forms';
4+
import { TestMaskComponent } from './utils/test-component.component';
5+
import { equal } from './utils/test-functions.component';
6+
7+
describe('Directive: Mask', () => {
8+
let fixture: ComponentFixture<TestMaskComponent>;
9+
let component: TestMaskComponent;
10+
11+
beforeEach(() => {
12+
TestBed.configureTestingModule({
13+
declarations: [TestMaskComponent],
14+
imports: [ReactiveFormsModule, NgxMaskModule.forRoot()],
15+
});
16+
fixture = TestBed.createComponent(TestMaskComponent);
17+
component = fixture.componentInstance;
18+
fixture.detectChanges();
19+
});
20+
21+
it('should display the default placeholder when not configured', () => {
22+
component.mask = '(000) 000-0000';
23+
component.showMaskTyped = true;
24+
equal('', '(___) ___-____', fixture);
25+
equal('2345678', '(234) 567-8___', fixture);
26+
27+
component.prefix = '+7';
28+
component.showMaskTyped = true;
29+
equal('', '+7(___) ___-____', fixture);
30+
equal('2345678', '+7(234) 567-8___', fixture);
31+
32+
component.mask = 'IP';
33+
component.prefix = '';
34+
component.showMaskTyped = true;
35+
equal('', '_._._._', fixture);
36+
equal('1921681', '192.168.1_', fixture);
37+
});
38+
39+
it('should display the modified placeholder when configured', () => {
40+
component.mask = '(000) 000-0000';
41+
component.showMaskTyped = true;
42+
component.placeHolderCharacter = '*';
43+
equal('', '(***) ***-****', fixture);
44+
equal('2345678', '(234) 567-8***', fixture);
45+
46+
component.prefix = '+7';
47+
component.showMaskTyped = true;
48+
equal('', '+7(***) ***-****', fixture);
49+
equal('2345678', '+7(234) 567-8***', fixture);
50+
51+
component.mask = 'IP';
52+
component.prefix = '';
53+
component.showMaskTyped = true;
54+
equal('', '*.*.*.*', fixture);
55+
equal('1921681', '192.168.1*', fixture);
56+
});
57+
});

src/app/ngx-mask/test/utils/test-component.component.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { IConfig } from 'public_api';
1818
[decimalMarker]="decimalMarker"
1919
[formControl]="form"
2020
[showMaskTyped]="showMaskTyped"
21+
[placeHolderCharacter]="placeHolderCharacter"
2122
[separatorLimit]="separatorLimit"
2223
[hiddenInput]="hiddenInput"
2324
[(ngModel)]="ngModelValue"
@@ -37,6 +38,7 @@ export class TestMaskComponent {
3738
public suffix: IConfig['suffix'] = '';
3839
public specialCharacters!: IConfig['specialCharacters'];
3940
public showMaskTyped: IConfig['showMaskTyped'] = false;
41+
public placeHolderCharacter: IConfig['placeHolderCharacter'] = '_';
4042
public hiddenInput: IConfig['hiddenInput'] = false;
4143
public separatorLimit: IConfig['separatorLimit'] = '';
4244
}

0 commit comments

Comments
 (0)