4

Code: https://codepen.io/anon/pen/MmjgNR
Problem: When editing the phone number with the mask, cursor leaps to the end.
Example: (123) 456-7890. When I try to remove the number 5 and make it 7, cursor moves immediately to the end: (123) 46-7890.

Let me know if you have any questions.
If you down vote please mention the reason so that I can correct.

AT82
  • 71,416
  • 24
  • 140
  • 167
mcvnpvsr
  • 161
  • 1
  • 6
  • The best way to avoid downvotes is to ask a good question. Please read this: https://stackoverflow.com/help/how-to-ask – Badacadabra Apr 24 '17 at 00:33
  • Instead of angular validation, try using jquery to validate and format the number on onblur event. That will prevent jumping at the end. – T.Shah Apr 24 '17 at 07:28
  • @T.Shah is there any way we can fix it with the existing angular validation because I have different directives for SSN,PHONE,DL etc. and thanks for you response. – mcvnpvsr Apr 24 '17 at 15:48

1 Answers1

3

Preface

I know literally nothing about AngularJS. I have never used it before. This is my first time I see it. I don’t know what it does. All it appears to do is add a massive layer of abstraction to obfuscate the code and justify increased IT spending on “insiders” who can see through this obfuscation. Your task would be much more simple without AngularJS. But, as I said, I don’t know what AngularJS is nor what it does, so I could be wrong.

The basic solution

The reason for the reported behaviour is that your script overwrites the <input> value every time the user types anything. The usual and basic solution is to store the caret position before the act of overwriting (element.val(...)):

var caretPosition = element[0].selectionStart;

...and restore it immediately after:

element[0].focus(); element[0].setSelectionRange(caretPosition, caretPosition);

Your script does contain a stub of a caret handling code already but it does literally nothing, it merely repeats its own unintended behaviour by intentionally moving the caret to the end of the string. This pointless act appears to be a hint to anyone who reuses the code to write their own caret handling code. Replace that stub with my code.

Live example

var app = angular.module('plunker', []);

app.controller('MainCtrl', function($scope) {$scope.name = 'Phone Number';});

app.directive('abcXyz', function($filter) {
   var mobileFilter, mobileReverse;
   mobileFilter = $filter('mobileFilter');
   mobileReverse = $filter('mobileReverse');
   return {
       restrict: 'A',
       require: 'ngModel',
       link: function(scope, element, attrs, modelCtrl) {
           var formatter, parser;
           parser = function(value) {
               var formatted;
               formatted = mobileReverse(value);
/* solution */ var caretPosition = element[0].selectionStart;
/* solution */ if (caretPosition === 4) caretPosition += 3;
/* solution */ if (caretPosition === 10) ++caretPosition;
               element.val(mobileFilter(formatted));
/* solution */ element[0].selectionStart = element[0].selectionEnd = caretPosition;
               return formatted;
           };
           modelCtrl.$formatters.push(formatter);
           return modelCtrl.$parsers.unshift(parser);
       }
   };
});

app.filter('mobileFilter', function() {
    return function(value) {
        var len, val;
        if (!value) return;
        val = value.toString().replace(/\D/g, "");
        len = val.length;
        if (len < 4) return val;
        else if (3 < len && len < 7) 
            return "(" + (val.substr(0, 3)) + ") " + (val.substr(3));
        else if (len > 6) 
            return "(" + (val.substr(0, 3)) + ") " + (val.substr(3, 3)) + 
            "-" + (val.substr(6, 4));
        return value;
    }
});

app.filter("mobileReverse", () => value => !!value && value.replace(/\D/g, "")
    .substr(0, 10));
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.10/angular.min.js">
</script>
<html ng-app="plunker">
 <body ng-controller="MainCtrl">
   <p>{{name}}!</p>
   <input type="tel" abc-xyz ng-model="formData.Phone" name="worktype" 
   maxlength="14" required="required" ng-pattern="(/[0-9-()]*[1-9][0-9-()]*/);" 
   autoComplete="off">
 </body>
</html>

A complete solution

The basic solution is an improvement but it’s still not perfect. It fails with backspace. User can sometimes add a letter or delete mandatory dash or bracket. It seems that you need a complex caret handler that has awareness of backspace, the filter and not one but two last caret positions. I have already included simple filter awareness in the basic example:

if (caretPosition === 4) caretPosition += 3;
if (caretPosition === 10) ++caretPosition;

but it is insufficient. At this point, I’m unable to deliver a complete caret handler to you but at least let me show you how to include backspace awareness in your AngularJS code:

  1. Add attribute ng-keydown="registerBackspace($event)" to HTML tag <input type="tel">.
  2. Replace your app.controller() call with this call:
app.controller('MainCtrl', function($scope) {
$scope.name = 'Phone Number';
$scope.registerBackspace = event => window.phoneBackspace = event.keyCode === 8;
});
  1. Now you have a global variable window.phoneBackspace which indicates whether the last key pressed in the phone input field was backspace (true or false).

I dislike global variables but I know nothing about AngularJS to figure out how to pass such information using its own functions (nor whether it allows doing so at all).

Final words

Upvote if you think that moderators are idiots.

Literature

Community
  • 1
  • 1
7vujy0f0hy
  • 8,741
  • 1
  • 28
  • 33