问题描述
我正在使用此格式化输入到(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>
1楼
在键入时修改用户的输入可能会分散注意力,并且总会导致您描述的问题。
通常,更容易实现,而不是让用户更难以修改UI。 电话号码的常见解决方案是并排放置三个输入字段,格式字符显示在中间。
使用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楼
你可以检查一下plunker ...我希望这是你想要的..
支持掩蔽和正则表达式..(是测试版)用法:#为两者,一个为字符,9为数字...(掩码过滤器不工作,因为接受将检查它..
<maskinput ng-mask-model="value" ng-mask="9 (999) 99-9999" ng-mask-regex="[^0-9]+"></maskinput>