Подтвердить что ты не робот

Запретить ввод любых дополнительных символов

Я использую эту Angular Директиву для форматирования телефонных номеров во вводе (999) 999-9999. Это отлично работает, пока пользователь не допустит ошибку и не изменяет введенный номер телефона.

Вы можете реплицировать эту проблему, выполнив приведенный ниже код и сделав следующее:

• Введите номер телефона (555) 123-4567
• Поместите курсор после символа 4 и удалите его.
• Введите 0 дважды.

Вы можете видеть, что 0 добавляется дважды, а символ 7 отбрасывается.

Другая проблема заключается в том, что пользователь пытается удалить и изменить символ 1. Их курсор сдвинут до самого конца ввода.

Я уверен, что это связано с проблемой с фильтром phonenumber, но я не уверен, как подойти к этому.

function MyCntl($scope) {
    $scope.myModel = {};
    $scope.myPrompt = "Input your phonenumber here!";
}

var phonenumberModule = angular.module('phonenumberModule', [])
 
	.directive('phonenumberDirective', ['$filter', function($filter) {
		/*
		Intended use:
			<phonenumber-directive placeholder='prompt' model='someModel.phonenumber'></phonenumber-directive>
		Where:
			someModel.phonenumber: {String} value which to bind only the numeric characters [0-9] entered
				ie, if user enters 617-2223333, value of 6172223333 will be bound to model
			prompt: {String} text to keep in placeholder when no numeric input entered
		*/
 
		function link(scope, element, attributes) {
 
			// scope.inputValue is the value of input element used in template
			scope.inputValue = scope.phonenumberModel;
 
			scope.$watch('inputValue', function(value, oldValue) {
				
				value = String(value);
				var number = value.replace(/[^0-9]+/g, '');
				scope.phonenumberModel = number;
				scope.inputValue = $filter('phonenumber')(number);
			});
		}
		
		return {
			link: link,
			restrict: 'E',
			scope: {
				phonenumberPlaceholder: '=placeholder',
				phonenumberModel: '=model',
			},
			//templateUrl: '/static/phonenumberModule/template.html',
			
            template: '<input name="phonenumber" ng-model="inputValue" type="tel" class="phonenumber" placeholder="{{phonenumberPlaceholder}}" title="Phonenumber (Format: (999) 9999-9999)">',
		};
	}])
 
	.filter('phonenumber', function() {
	    /* 
	    Format phonenumber as: c (xxx) xxx-xxxx
	    	or as close as possible if phonenumber length is not 10
	    	if c is not '1' (country code not USA), does not use country code
	    */
	    
	    return function (number) {
		    /* 
		    @param {Number | String} number - Number that will be formatted as telephone number
		    Returns formatted number: (###) ###-####
		    	if number.length < 4: ###
		    	else if number.length < 7: (###) ###
 
		    Does not handle country codes that are not '1' (USA)
		    */
	        if (!number) { return ''; }
 
	        number = String(number);
 
	        // Will return formattedNumber. 
	        // If phonenumber isn't longer than an area code, just show number
	        var formattedNumber = number;
 
			// if the first character is '1', strip it out and add it back
			var c = (number[0] == '1') ? '1 ' : '';
			number = number[0] == '1' ? number.slice(1) : number;
 
			// # (###) ###-#### as c (area) front-end
			var area = number.substring(0,3);
			var front = number.substring(3, 6);
			var end = number.substring(6, 10);
 
			if (front) {
				formattedNumber = (c + "(" + area + ") " + front);	
			}
			if (end) {
				formattedNumber += ("-" + end);
			}
			return formattedNumber;
	    };
	});
.phonenumber {
    min-width: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="phonenumberModule" ng-controller="MyCntl">
    <p>phonenumber value: {{ myModel.phonenumber }}</p>
    <p>formatted phonenumber: {{ myModel.phonenumber | phonenumber }}</p>
    <form name="phoneForm">
        <phonenumber-directive placeholder="myPrompt" model='myModel.phonenumber'></phonenumber-directive>
        <div ng-show="phoneForm.phonenumber.$error.minlength">
          <p>Enter a valid phone number</p>
        </div>
    </form>
</div>
4b9b3361

Ответ 1

Изменение пользовательского ввода по типу может отвлекать и всегда приводит к проблемам, которые вы описываете.

В общем, проще реализовать и менее разочаровывать пользователя, чтобы изменить пользовательский интерфейс. Общим решением для телефонных номеров является размещение трех полей ввода бок о бок, причем символы форматирования отображаются между ними.

Используя Angular, можно создать одну директиву, чтобы обернуть этот механизм ввода нескольких частей и выставить один конкатенированный результат для остальной части приложения.

Ответ 2

Я думаю, вы должны использовать редактируемое поле (например, ввод текста типа), чтобы ввести число и поле только для чтения (например, метку), чтобы показать его форматирование, потому что отформатированное значение является только проблемой отображения, поэтому оно не должны редактироваться.

Итак, я изменил ваш фрагмент, чтобы сделать это.

function MyCntl($scope) {
    $scope.myModel = {};
    $scope.myPrompt = "Input your phonenumber here!";
}

var phonenumberModule = angular.module('phonenumberModule', [])
 
	.directive('phonenumberDirective', ['$filter', function($filter) {
		/*
		Intended use:
			<phonenumber-directive placeholder='prompt' model='someModel.phonenumber'></phonenumber-directive>
		Where:
			someModel.phonenumber: {String} value which to bind only the numeric characters [0-9] entered
				ie, if user enters 617-2223333, value of 6172223333 will be bound to model
			prompt: {String} text to keep in placeholder when no numeric input entered
		*/
 
		function link(scope, element, attributes) {
 
			// scope.inputValue is the value of input element used in template
			scope.inputValue = scope.phonenumberModel;
 
			scope.$watch('inputValue', function(value, oldValue) {
				
				value = String(value);
                oldValue = String(oldValue);
                // get rid of input non digits chars
				var number = value.replace(/[^0-9]+/g, '');
                var oldNumber = oldValue.replace(/[^0-9]+/g, '');
				
                var filteredNumber = $filter('phonenumber')(number);
                // get rid of filter non digits chars
                scope.phonenumberModel = filteredNumber.replace(/[^0-9]+/g, '');
                inputValue = scope.phonenumberModel;
                var filteredOldNumber = $filter('phonenumber')(oldNumber);
                if(filteredNumber.length === filteredOldNumber.length) {
                    scope.maxlength = filteredNumber.length;
                }
                else {
                    scope.maxlength = Math.max(number.length, 11);
                }                    
			});
		}
		
		return {
			link: link,
			restrict: 'E',
			scope: {
				phonenumberPlaceholder: '=placeholder',
				phonenumberModel: '=model',
			},
			//templateUrl: '/static/phonenumberModule/template.html',
			
            template: '<input name="phonenumber" ng-model="inputValue" type="tel" maxlength="{{maxlength || 11}}" class="phonenumber" placeholder="{{phonenumberPlaceholder}}" title="Phonenumber (Format: (999) 9999-9999)"> <label>Formatted:{{inputValue | phonenumber}}</label>',
		};
	}])
 
	.filter('phonenumber', function() {
	    /* 
	    Format phonenumber as: c (xxx) xxx-xxxx
	    	or as close as possible if phonenumber length is not 10
	    	if c is not '1' (country code not USA), does not use country code
	    */
	    
	    return function (number) {
		    /* 
		    @param {Number | String} number - Number that will be formatted as telephone number
		    Returns formatted number: (###) ###-####
		    	if number.length < 4: ###
		    	else if number.length < 7: (###) ###
 
		    Does not handle country codes that are not '1' (USA)
		    */
	        if (!number) { return ''; }
 
	        number = String(number);
 
	        // Will return formattedNumber. 
	        // If phonenumber isn't longer than an area code, just show number
	        var formattedNumber = number;
 
			// if the first character is '1', strip it out and add it back
			var c = (number[0] == '1') ? '1 ' : '';
			number = number[0] == '1' ? number.slice(1) : number;
 
			// # (###) ###-#### as c (area) front-end
			var area = number.substring(0,3);
			var front = number.substring(3, 6);
			var end = number.substring(6, 10);
 
			if (front) {
				formattedNumber = (c + "(" + area + ") " + front);	
			}
			if (end) {
				formattedNumber += ("-" + end);
			}
			return formattedNumber;
	    };
	});
.phonenumber {
    min-width: 200px;
}
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.23/angular.min.js"></script>

<div ng-app="phonenumberModule" ng-controller="MyCntl">
    <p>phonenumber value: {{ myModel.phonenumber }}</p>
    <p>formatted phonenumber: {{ myModel.phonenumber | phonenumber }}</p>
    <form name="phoneForm">
        <phonenumber-directive placeholder="myPrompt" model='myModel.phonenumber'></phonenumber-directive>
        <div ng-show="phoneForm.phonenumber.$error.minlength">
          <p>Enter a valid phone number</p>
        </div>
    </form>
</div>

Ответ 3

Вы можете проверить плункер, пожалуйста... Я надеюсь, что это то, что вам нужно.

http://plnkr.co/edit/0IBJBRb2JtvZnq6PtBiV?p=preview

поддержка маскировки и регулярного выражения.. (это бета) Использование: # для обоих, a для символов, 9 для чисел... (фильтр маски не работает, как принято, проверит его.

 <maskinput ng-mask-model="value" ng-mask="9 (999) 99-9999" ng-mask-regex="[^0-9]+"></maskinput>