Search code examples
angularjsangularjs-directiveangularjs-scope

AngularJS: Cursor is moving to last position when model is transformed


I am using zipcode directive which is accepting 9 digit US zip code and formatting it.

app.directive('formatZipCode', function () {
    return {
        require: 'ngModel',
        link: function (scope, element, attr, ngModelCtrl) {
            function fromUser(text) {
                if (text) {
                    var transformedInput = text.replace(/[^0-9]/g, '');
                    if (transformedInput.length > 9) {
                        transformedInput = transformedInput.slice(0, 9);
                    }
                    if (transformedInput.length > 5) {
                        transformedInput = transformedInput.slice(0, 5) + "-" + transformedInput.slice(5);
                    }

                    if (transformedInput !== text) {
                        ngModelCtrl.$setViewValue(transformedInput);
                        ngModelCtrl.$render();
                    }
                    return transformedInput;
                }
                return undefined;
            }


            ngModelCtrl.$parsers.push(fromUser);
        }
    };
});

when I am removing any number from zipcode, cursor position moves back to last position. When I delete third number cursor moves to last number

How to retain the cursor position?


Solution

  • I have resolved this by using caret position. Remember the caret position and after formatting input assign the caret position again.

    app.directive('formatZipCode', function () {
        return {
            require: 'ngModel',
            link: function (scope, element, attr, ngModelCtrl) {
                function fromUser(text) {
                    if (text) {
                        var transformedInput = text.replace(/[^0-9]/g, '');
                        if (transformedInput.length > 9) {
                            transformedInput = transformedInput.slice(0, 9);
                        }
                        var caretPosition = element[0].selectionStart || undefined;
                        if (transformedInput.length > 5) {                     
                            var realposition = caretPosition == 6 ? caretPosition + 1 : caretPosition;
                            transformedInput = transformedInput.slice(0, 5) + "-" + transformedInput.slice(5);
                        }
    
                        if (transformedInput !== text) {                      
                            ngModelCtrl.$setViewValue(transformedInput);
                            ngModelCtrl.$render();
                            if (typeof caretPosition === 'number') {
                                element[0].selectionStart = element[0].selectionEnd = realposition || caretPosition;
                            }
                            else {
                                element[0].selectionStart = element[0].selectionEnd = 0;
                            }
                        }
                        return transformedInput;
                    }
                    return undefined;
                }
    
                ngModelCtrl.$parsers.push(fromUser);
            }
        };
    });