전화 번호를 허용하는 입력에 대한 마스크?
Angular 2를 수 합니까?input
전화 번호 항목과 같은 필드(123) 123-4567
?
각도 5 및 6:
각진 5 및 6 권장 방법은 호스트 속성 대신 @HostBindings 및 @HostListeners를 사용하는 것입니다.
호스트 제거 및 @HostListener 추가
@HostListener('ngModelChange', ['$event'])
onModelChange(event) {
this.onInputChange(event, false);
}
@HostListener('keydown.backspace', ['$event'])
keydownBackspace(event) {
this.onInputChange(event.target.value, true);
}
온라인 스택블리츠 작업 링크: https://angular6-phone-mask.stackblitz.io
스택블리츠 코드 예: https://stackblitz.com/edit/angular6-phone-mask
공식 문서 링크 https://angular.io/guide/attribute-directives#respond-to-user-initiated-events
각도 2 및 4:
원래의
당신이 할 수 있는 한 가지 방법은 주사하는 지시를 사용하는 것입니다.NgControl
합니다.
(자세한 내용은 인라인 주석 참조)
@Directive({
selector: '[ngModel][phone]',
host: {
'(ngModelChange)': 'onInputChange($event)',
'(keydown.backspace)': 'onInputChange($event.target.value, true)'
}
})
export class PhoneMask {
constructor(public model: NgControl) {}
onInputChange(event, backspace) {
// remove all mask characters (keep only numeric)
var newVal = event.replace(/\D/g, '');
// special handling of backspace necessary otherwise
// deleting of non-numeric characters is not recognized
// this laves room for improvement for example if you delete in the
// middle of the string
if (backspace) {
newVal = newVal.substring(0, newVal.length - 1);
}
// don't show braces for empty value
if (newVal.length == 0) {
newVal = '';
}
// don't show braces for empty groups at the end
else if (newVal.length <= 3) {
newVal = newVal.replace(/^(\d{0,3})/, '($1)');
} else if (newVal.length <= 6) {
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})/, '($1) ($2)');
} else {
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})(.*)/, '($1) ($2)-$3');
}
// set the new value
this.model.valueAccessor.writeValue(newVal);
}
}
@Component({
selector: 'my-app',
providers: [],
template: `
<form [ngFormModel]="form">
<input type="text" phone [(ngModel)]="data" ngControl="phone">
</form>
`,
directives: [PhoneMask]
})
export class App {
constructor(fb: FormBuilder) {
this.form = fb.group({
phone: ['']
})
}
}
가장 간단한 해결책은 ngx-mask를 추가하는 것이라고 생각합니다.
npm i --save ngx-mask
그러면 할 수 있습니다.
<input type='text' mask='(000) 000-0000' >
OR
<p>{{ phoneVar | mask: '(000) 000-0000' }} </p>
앵귤러 4+
모든 마스크를 수신할 수 있고 다음 값을 기반으로 동적으로 마스크를 정의할 수 있는 일반적인 지침을 만들었습니다.
mask.sys.ts:
import { Directive, EventEmitter, HostListener, Input, Output } from '@angular/core';
import { NgControl } from '@angular/forms';
import { MaskGenerator } from '../interfaces/mask-generator.interface';
@Directive({
selector: '[spMask]'
})
export class MaskDirective {
private static readonly ALPHA = 'A';
private static readonly NUMERIC = '9';
private static readonly ALPHANUMERIC = '?';
private static readonly REGEX_MAP = new Map([
[MaskDirective.ALPHA, /\w/],
[MaskDirective.NUMERIC, /\d/],
[MaskDirective.ALPHANUMERIC, /\w|\d/],
]);
private value: string = null;
private displayValue: string = null;
@Input('spMask')
public maskGenerator: MaskGenerator;
@Input('spKeepMask')
public keepMask: boolean;
@Input('spMaskValue')
public set maskValue(value: string) {
if (value !== this.value) {
this.value = value;
this.defineValue();
}
};
@Output('spMaskValueChange')
public changeEmitter = new EventEmitter<string>();
@HostListener('input', ['$event'])
public onInput(event: { target: { value?: string }}): void {
let target = event.target;
let value = target.value;
this.onValueChange(value);
}
constructor(private ngControl: NgControl) { }
private updateValue(value: string) {
this.value = value;
this.changeEmitter.emit(value);
MaskDirective.delay().then(
() => this.ngControl.control.updateValueAndValidity()
);
}
private defineValue() {
let value: string = this.value;
let displayValue: string = null;
if (this.maskGenerator) {
let mask = this.maskGenerator.generateMask(value);
if (value != null) {
displayValue = MaskDirective.mask(value, mask);
value = MaskDirective.processValue(displayValue, mask, this.keepMask);
}
} else {
displayValue = this.value;
}
MaskDirective.delay().then(() => {
if (this.displayValue !== displayValue) {
this.displayValue = displayValue;
this.ngControl.control.setValue(displayValue);
return MaskDirective.delay();
}
}).then(() => {
if (value != this.value) {
return this.updateValue(value);
}
});
}
private onValueChange(newValue: string) {
if (newValue !== this.displayValue) {
let displayValue = newValue;
let value = newValue;
if ((newValue == null) || (newValue.trim() === '')) {
value = null;
} else if (this.maskGenerator) {
let mask = this.maskGenerator.generateMask(newValue);
displayValue = MaskDirective.mask(newValue, mask);
value = MaskDirective.processValue(displayValue, mask, this.keepMask);
}
this.displayValue = displayValue;
if (newValue !== displayValue) {
this.ngControl.control.setValue(displayValue);
}
if (value !== this.value) {
this.updateValue(value);
}
}
}
private static processValue(displayValue: string, mask: string, keepMask: boolean) {
let value = keepMask ? displayValue : MaskDirective.unmask(displayValue, mask);
return value
}
private static mask(value: string, mask: string): string {
value = value.toString();
let len = value.length;
let maskLen = mask.length;
let pos = 0;
let newValue = '';
for (let i = 0; i < Math.min(len, maskLen); i++) {
let maskChar = mask.charAt(i);
let newChar = value.charAt(pos);
let regex: RegExp = MaskDirective.REGEX_MAP.get(maskChar);
if (regex) {
pos++;
if (regex.test(newChar)) {
newValue += newChar;
} else {
i--;
len--;
}
} else {
if (maskChar === newChar) {
pos++;
} else {
len++;
}
newValue += maskChar;
}
}
return newValue;
}
private static unmask(maskedValue: string, mask: string): string {
let maskLen = (mask && mask.length) || 0;
return maskedValue.split('').filter(
(currChar, idx) => (idx < maskLen) && MaskDirective.REGEX_MAP.has(mask[idx])
).join('');
}
private static delay(ms: number = 0): Promise<void> {
return new Promise(resolve => setTimeout(() => resolve(), ms)).then(() => null);
}
}
(NgModule에서 선언하는 것을 잊지 마십시오.
는 마크의숫문자다같음습다니과는자스▁in다▁the입니다.9
그래서 당신의 마스크는.(999) 999-9999
변경할 수 .NUMERIC
(을 하는경로필정드적으로 한다면)0
의 마스크는 합니다.(000) 000-0000
예를 들어).
값은 마스크와 함께 표시되지만 마스크 없이 구성 요소 필드에 저장됩니다(이 경우 바람직한 동작입니다).다음을 사용하여 마스크와 함께 저장할 수 있습니다.[spKeepMask]="true"
.
는 지문은다구객수신다니합체를현는하를 합니다.MaskGenerator
interface 이름
가면을 쓴interface.ts:
export interface MaskGenerator {
generateMask: (value: string) => string;
}
이렇게 하면 신용 카드와 같이 값을 기반으로 동적으로 마스크를 정의할 수 있습니다.
마스크를 저장할 유틸리티 클래스를 만들었지만 구성 요소에서 직접 지정할 수도 있습니다.
my-mask.sys.ts:
export class MyMaskUtil {
private static PHONE_SMALL = '(999) 999-9999';
private static PHONE_BIG = '(999) 9999-9999';
private static CPF = '999.999.999-99';
private static CNPJ = '99.999.999/9999-99';
public static PHONE_MASK_GENERATOR: MaskGenerator = {
generateMask: () => MyMaskUtil.PHONE_SMALL,
}
public static DYNAMIC_PHONE_MASK_GENERATOR: MaskGenerator = {
generateMask: (value: string) => {
return MyMaskUtil.hasMoreDigits(value, MyMaskUtil.PHONE_SMALL) ?
MyMaskUtil.PHONE_BIG :
MyMaskUtil.PHONE_SMALL;
},
}
public static CPF_MASK_GENERATOR: MaskGenerator = {
generateMask: () => MyMaskUtil.CPF,
}
public static CNPJ_MASK_GENERATOR: MaskGenerator = {
generateMask: () => MyMaskUtil.CNPJ,
}
public static PERSON_MASK_GENERATOR: MaskGenerator = {
generateMask: (value: string) => {
return MyMaskUtil.hasMoreDigits(value, MyMaskUtil.CPF) ?
MyMaskUtil.CNPJ :
MyMaskUtil.CPF;
},
}
private static hasMoreDigits(v01: string, v02: string): boolean {
let d01 = this.onlyDigits(v01);
let d02 = this.onlyDigits(v02);
let len01 = (d01 && d01.length) || 0;
let len02 = (d02 && d02.length) || 0;
let moreDigits = (len01 > len02);
return moreDigits;
}
private static onlyDigits(value: string): string {
let onlyDigits = (value != null) ? value.replace(/\D/g, '') : null;
return onlyDigits;
}
}
할 수 .spMaskValue
에 ngModel
반응형이 하지만응반이아니면라형,면아니라▁use▁but,▁is이,ngModel
아래의 예와 같이 주입으로 인해 제공자가 없다는 오류를 받지 않도록 아무것도 사용하지 않습니다.NgControl
지침; 반응형에는 포함할 필요가 없습니다.ngModel
):
my.component.ts:
@Component({ ... })
export class MyComponent {
public phoneValue01: string = '1231234567';
public phoneValue02: string;
public phoneMask01 = MyMaskUtil.PHONE_MASK_GENERATOR;
public phoneMask02 = MyMaskUtil.DYNAMIC_PHONE_MASK_GENERATOR;
}
my.component.component:
<span>Phone 01 ({{ phoneValue01 }}):</span><br>
<input type="text" [(spMaskValue)]="phoneValue01" [spMask]="phoneMask01" ngModel>
<br><br>
<span>Phone 02 ({{ phoneValue02 }}):</span><br>
<input type="text" [(spMaskValue)]="phoneValue02" [spMask]="phoneMask02" [spKeepMask]="true" ngModel>
를 보세요.phone02
더 또한 이 "1자리"라는 것을 합니다. 또한 저장되었는지 확인합니다.phone01
마스크 없음)
저는 그것을 일반적인 입력과 함께 테스트했습니다.ionic
입력)ion-input
), 반응성(with), 반응성(with)을 포함합니다.formControlName
는다가 아닌formControl
및 양식 및 비선택적 형식입니다.
'angular2-text-mask'의 TextMask 모듈을 사용하여 이 작업을 수행합니다.
내 것은 갈라졌지만 당신은 아이디어를 얻을 수 있습니다.
NPM NodeJS를 사용한 패키지
"dependencies": {
"angular2-text-mask": "8.0.0",
HTML
<input *ngIf="column?.type =='areaCode'" type="text" [textMask]="{mask: areaCodeMask}" [(ngModel)]="areaCodeModel">
<input *ngIf="column?.type =='phone'" type="text" [textMask]="{mask: phoneMask}" [(ngModel)]="phoneModel">
내부 구성요소
public areaCodeModel = '';
public areaCodeMask = ['(', /[1-9]/, /\d/, /\d/, ')'];
public phoneModel = '';
public phoneMask = [/\d/, /\d/, /\d/, '-', /\d/, /\d/, /\d/, /\d/];
반응형
위의 @Günter Zöchbauer의 답변 외에도 다음과 같이 시도해 보았는데 효과가 있는 것 같지만 효율적인 방법인지는 잘 모르겠습니다.
사용합니다valueChanges
구독을 통해 반응형의 변경 이벤트를 청취할 수 있습니다.백스페이스의 특별한 처리를 위해, 나는 다음과 같은 정보를 얻습니다.data
subscribe에서 하고 구독에확다니합인.userForm.value.phone(from [formGroup]="userForm")
그 순간 데이터는 새 값으로 변경되지만 후자는 아직 설정되지 않았기 때문에 이전 값을 참조하기 때문입니다.데이터가 이전 값보다 작으면 사용자는 입력에서 문자를 제거해야 합니다.과 같이 합니다.
시작:newVal = newVal.replace(/^(\d{0,3})/, '($1)');
대상:newVal = newVal.replace(/^(\d{0,3})/, '($1');
그렇지 않으면 위에서 언급한 귄터 쇠흐바우어가 숫자가 아닌 문자를 삭제하는 것은 인식되지 않습니다. 왜냐하면 입력에서 괄호를 제거할 때 숫자는 여전히 동일하게 유지되고 패턴 일치에서 괄호를 다시 추가하기 때문입니다.
컨트롤러:
import { Component,OnInit } from '@angular/core';
import { FormGroup,FormBuilder,AbstractControl,Validators } from '@angular/forms';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit{
constructor(private fb:FormBuilder) {
this.createForm();
}
createForm(){
this.userForm = this.fb.group({
phone:['',[Validators.pattern(/^\(\d{3}\)\s\d{3}-\d{4}$/),Validators.required]],
});
}
ngOnInit() {
this.phoneValidate();
}
phoneValidate(){
const phoneControl:AbstractControl = this.userForm.controls['phone'];
phoneControl.valueChanges.subscribe(data => {
/**the most of code from @Günter Zöchbauer's answer.*/
/**we remove from input but:
@preInputValue still keep the previous value because of not setting.
*/
let preInputValue:string = this.userForm.value.phone;
let lastChar:string = preInputValue.substr(preInputValue.length - 1);
var newVal = data.replace(/\D/g, '');
//when removed value from input
if (data.length < preInputValue.length) {
/**while removing if we encounter ) character,
then remove the last digit too.*/
if(lastChar == ')'){
newVal = newVal.substr(0,newVal.length-1);
}
if (newVal.length == 0) {
newVal = '';
}
else if (newVal.length <= 3) {
/**when removing, we change pattern match.
"otherwise deleting of non-numeric characters is not recognized"*/
newVal = newVal.replace(/^(\d{0,3})/, '($1');
} else if (newVal.length <= 6) {
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})/, '($1) $2');
} else {
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})(.*)/, '($1) $2-$3');
}
//when typed value in input
} else{
if (newVal.length == 0) {
newVal = '';
}
else if (newVal.length <= 3) {
newVal = newVal.replace(/^(\d{0,3})/, '($1)');
} else if (newVal.length <= 6) {
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})/, '($1) $2');
} else {
newVal = newVal.replace(/^(\d{0,3})(\d{0,3})(.*)/, '($1) $2-$3');
}
}
this.userForm.controls['phone'].setValue(newVal,{emitEvent: false});
});
}
}
템플릿:
<form [formGroup]="userForm" novalidate>
<div class="form-group">
<label for="tel">Tel:</label>
<input id="tel" formControlName="phone" maxlength="14">
</div>
<button [disabled]="userForm.status == 'INVALID'" type="submit">Send</button>
</form>
갱신하다
문자열 중간에 백스페이스를 사용하면서 커서 위치를 유지할 수 있는 방법이 있습니까?현재, 그것은 끝까지 다시 점프합니다.
»<input id="tel" formControlName="phone" #phoneRef>
그리고 renderer2#RootElement를 선택하여 구성 요소의 네이티브 요소를 가져옵니다.
따라서 다음을 사용하여 커서 위치를 얻을 수 있습니다.
let start = this.renderer.selectRootElement('#tel').selectionStart;
let end = this.renderer.selectRootElement('#tel').selectionEnd;
그런 다음 입력을 새 값으로 업데이트한 후 적용할 수 있습니다.
this.userForm.controls['phone'].setValue(newVal,{emitEvent: false});
//keep cursor the appropriate position after setting the input above.
this.renderer.selectRootElement('#tel').setSelectionRange(start,end);
업데이트 2
이런 종류의 논리를 구성 요소보다는 지침 내부에 넣는 것이 더 나을 것입니다.
저는 또한 그 논리를 지시문에 넣었습니다.이렇게 하면 다른 요소에 쉽게 적용할 수 있습니다.
참고: 패턴에 따라 다릅니다.
지시문을 사용하여 수행할 수 있습니다.아래는 제가 만든 입력 마스크의 플랭크입니다.
https://plnkr.co/edit/hRsmd0EKci6rjGmnYFRr?p=preview
코드:
import {Directive, Attribute, ElementRef, OnInit, OnChanges, Input, SimpleChange } from 'angular2/core';
import {NgControl, DefaultValueAccessor} from 'angular2/common';
@Directive({
selector: '[mask-input]',
host: {
//'(keyup)': 'onInputChange()',
'(click)': 'setInitialCaretPosition()'
},
inputs: ['modify'],
providers: [DefaultValueAccessor]
})
export class MaskDirective implements OnChanges {
maskPattern: string;
placeHolderCounts: any;
dividers: string[];
modelValue: string;
viewValue: string;
intialCaretPos: any;
numOfChar: any;
@Input() modify: any;
constructor(public model: NgControl, public ele: ElementRef, @Attribute("mask-input") maskPattern: string) {
this.dividers = maskPattern.replace(/\*/g, "").split("");
this.dividers.push("_");
this.generatePattern(maskPattern);
this.numOfChar = 0;
}
ngOnChanges(changes: { [propertyName: string]: SimpleChange }) {
this.onInputChange(changes);
}
onInputChange(changes: { [propertyName: string]: SimpleChange }) {
this.modelValue = this.getModelValue();
var caretPosition = this.ele.nativeElement.selectionStart;
if (this.viewValue != null) {
this.numOfChar = this.getNumberOfChar(caretPosition);
}
var stringToFormat = this.modelValue;
if (stringToFormat.length < 10) {
stringToFormat = this.padString(stringToFormat);
}
this.viewValue = this.format(stringToFormat);
if (this.viewValue != null) {
caretPosition = this.setCaretPosition(this.numOfChar);
}
this.model.viewToModelUpdate(this.modelValue);
this.model.valueAccessor.writeValue(this.viewValue);
this.ele.nativeElement.selectionStart = caretPosition;
this.ele.nativeElement.selectionEnd = caretPosition;
}
generatePattern(patternString) {
this.placeHolderCounts = (patternString.match(/\*/g) || []).length;
for (var i = 0; i < this.placeHolderCounts; i++) {
patternString = patternString.replace('*', "{" + i + "}");
}
this.maskPattern = patternString;
}
format(s) {
var formattedString = this.maskPattern;
for (var i = 0; i < this.placeHolderCounts; i++) {
formattedString = formattedString.replace("{" + i + "}", s.charAt(i));
}
return formattedString;
}
padString(s) {
var pad = "__________";
return (s + pad).substring(0, pad.length);
}
getModelValue() {
var modelValue = this.model.value;
if (modelValue == null) {
return "";
}
for (var i = 0; i < this.dividers.length; i++) {
while (modelValue.indexOf(this.dividers[i]) > -1) {
modelValue = modelValue.replace(this.dividers[i], "");
}
}
return modelValue;
}
setInitialCaretPosition() {
var caretPosition = this.setCaretPosition(this.modelValue.length);
this.ele.nativeElement.selectionStart = caretPosition;
this.ele.nativeElement.selectionEnd = caretPosition;
}
setCaretPosition(num) {
var notDivider = true;
var caretPos = 1;
for (; num > 0; caretPos++) {
var ch = this.viewValue.charAt(caretPos);
if (!this.isDivider(ch)) {
num--;
}
}
return caretPos;
}
isDivider(ch) {
for (var i = 0; i < this.dividers.length; i++) {
if (ch == this.dividers[i]) {
return true;
}
}
}
getNumberOfChar(pos) {
var num = 0;
var containDividers = false;
for (var i = 0; i < pos; i++) {
var ch = this.modify.charAt(i);
if (!this.isDivider(ch)) {
num++;
}
else {
containDividers = true;
}
}
if (containDividers) {
return num;
}
else {
return this.numOfChar;
}
}
}
참고: 여전히 몇 가지 버그가 있습니다.
귄터 조흐바우어의 답변과 오래된 바닐라-JS를 결합하면, 여기 (123) 456-7890 형식을 지원하는 두 줄의 논리가 있는 지침이 있습니다.
반응형: 플렁크
import { Directive, Output, EventEmitter } from "@angular/core";
import { NgControl } from "@angular/forms";
@Directive({
selector: '[formControlName][phone]',
host: {
'(ngModelChange)': 'onInputChange($event)'
}
})
export class PhoneMaskDirective {
@Output() rawChange:EventEmitter<string> = new EventEmitter<string>();
constructor(public model: NgControl) {}
onInputChange(value) {
var x = value.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})(\d{0,4})/);
var y = !x[2] ? x[1] : '(' + x[1] + ') ' + x[2] + (x[3] ? '-' + x[3] : '');
this.model.valueAccessor.writeValue(y);
this.rawChange.emit(rawValue);
}
}
템플릿 기반 양식: 플렁크
import { Directive } from "@angular/core";
import { NgControl } from "@angular/forms";
@Directive({
selector: '[ngModel][phone]',
host: {
'(ngModelChange)': 'onInputChange($event)'
}
})
export class PhoneMaskDirective {
constructor(public model: NgControl) {}
onInputChange(value) {
var x = value.replace(/\D/g, '').match(/(\d{0,3})(\d{0,3})(\d{0,4})/);
value = !x[2] ? x[1] : '(' + x[1] + ') ' + x[2] + (x[3] ? '-' + x[3] : '');
this.model.valueAccessor.writeValue(value);
}
}
// phone (123) 123-4567
var cleavePhone = new Cleave('.input-phone', {
//prefix: '(123)',
delimiters: ['(',') ','-'],
blocks: [0, 3, 3, 4]
});
데모: https://jsfiddle.net/emirM/a8fogse1/
바퀴를 다시 만들 필요가 없습니다!통화 마스크를 사용합니다. TextMaskModule과 달리 이 마스크는 숫자 입력 유형과 함께 작동하며 구성이 매우 쉽습니다.제가 직접 지시를 내릴 때, 저는 계산을 하기 위해 숫자와 문자열 사이를 계속 변환해야 한다는 것을 알았습니다.시간을 절약하세요.링크는 다음과 같습니다.
https://github.com/cesarrew/ng2-currency-mask
<input type="text" formControlName="gsm" (input)="formatGsm($event.target.value)">
formatGsm(inputValue: String): String {
const value = inputValue.replace(/[^0-9]/g, ''); // remove except digits
let format = '(***) *** ** **'; // You can change format
for (let i = 0; i < value.length; i++) {
format = format.replace('*', value.charAt(i));
}
if (format.indexOf('*') >= 0) {
format = format.substring(0, format.indexOf('*'));
}
return format.trim();
}
클래스 MyMaskUtil {} 내보내기
public static MASK_CEP(value: string):string {
return value = value.replace(/^(\d{5})(\d{3}).*/, '$1-$2');
}
public static MASK_TELEFONE(value: string):string {
return value = value.replace(/^(\d{2})(\d{5})(\d{4}).*/, '($1)$2-$3');
}
public static MASK_CPF(value: string):string {
return value = value.replace(/^(\d{3})^(\d{3})^(\d{3})(\d{2}).*/, '$1.$2.$3-$4');
}
}
레제바
크레디토스 에닐슨 필호
언급URL : https://stackoverflow.com/questions/37800841/mask-for-an-input-to-allow-phone-numbers
'source' 카테고리의 다른 글
파워셸에서 크롬 개체 인스턴스화 (0) | 2023.08.15 |
---|---|
CLOB 열에서 Oracle과 함께 GROUP BY를 사용하는 방법은 무엇입니까? (0) | 2023.08.15 |
장고 >= 3.1 및 is_dll (0) | 2023.08.15 |
자바.java.javaNoClassDefFoundError: org/springframework/data/repository/config/BootstrapMode (0) | 2023.08.15 |
CSS를 사용하여 배경 이미지를 뒤집는 방법은 무엇입니까? (0) | 2023.08.15 |