Bug in Chrome causing issues with autofilling fields in AngularJS applications

Seeking a solution to address a bug noticed while utilizing a custom Angular directive in conjunction with Chrome's autofill feature. The directive is designed for a phone number field, automatically adding dashes "-" to enhance user experience by eliminating the need for manual dash input.

Displayed below is the directive:

app.directive("phoneNumberValidator", function () {
    return {
        require: "ngModel",
        restrict: "A",
        link: function (scope, elem, attrs, ctrl) {

            var domElement = elem[0]; // Access DOM element
            var phoneNumberRegex = new RegExp("\\d{3}\\-\\d{3}\\-\\d{4}"); // Define phone number regex pattern
            var cursorIndex; // Index for cursor placement

            // Create parser to modify and validate phone numbers
            ctrl.$parsers.push(function (value) {

                if (typeof value === "undefined" || value === null || value == "") {
                    ctrl.$setValidity('invalidFormat', true);
                    return undefined;
                }

                var prevValue, nextValue;

                prevValue = value;
                nextValue = value.replace(/[\D]/gi, "");

                if (nextValue.length >= 4 && nextValue.length <= 6) {
                    nextValue = nextValue.replace(/(\d{3})(\d{3})?/, "$1-$2");
                } else if (nextValue.length >= 7 && nextValue.length <= 10) {
                    nextValue = nextValue.replace(/(\d{3})(\d{3})(\d{4})?/, "$1-$2-$3");
                }

                cursorIndex = domElement.selectionStart;

                if (prevValue != nextValue) {
                    ctrl.$setViewValue(nextValue);
                } else {
                    ctrl.$render();
                }

                if (cursorIndex == 4 || cursorIndex == 8) {
                    cursorIndex = cursorIndex + 1;
                }

                var valid = phoneNumberRegex.test(value); 
                ctrl.$setValidity('invalidFormat', valid); 
                domElement.setSelectionRange(cursorIndex, cursorIndex);

                return value; 
            });
        }
    }
});

The issue arises when Chrome autofills the field. Using the Batarang extension (Batarang Extension Link), I can observe the scope values within the page. If Chrome auto-populates my phone number field with "1234567899," the corresponding Angular phone field's value in my $scope remains as 1234567899 instead of 123-546-7899.

Inserting a breakpoint in my directive confirms that it executes upon Chrome's autofill action, however, the $scope.PhoneNumber field retains the unfilled value. Essentially, the $viewModel updates correctly during autofill, but not the $modelValue.

Is there a method to programmatically adjust the $modelValue to display the correct value in $scope.PhoneNumber post Chrome autofill?

PLUNKR Demo

Answer №1

This solution functions as anticipated, however, it can be quite perplexing. In essence, $setViewValue should not be invoked within a parser because doing so triggers the entire $parsers and $validators pipeline up to the actual model value. So what occurs? If the value differs, you will call another $setViewValue. Since the pipeline operates synchronously, it re-runs the $parsers before the initial run concludes! Therefore, the return value from the first execution of the parser is the one that actually gets set to the model. I would recommend refraining from calling $setViewValue in the parser, but instead setting the $viewValue and invoking $render.

The issue is also observable when autofill is absent (or even with simple paste). Try entering 1234 separately, and you will notice that the model displays 1234 since that is the original value. Only upon entering 5 will the value become 123-45, as at that point the view has already been updated with the dash.

It essentially exposes a flaw in the angular API. There is no straightforward method to transform the view, leading people to misuse the parsers. In terms of technique, my suggestion would be to override the $setViewValue function so that the value passed to the parsers is already correctly formatted.

For an updated example, visit: http://plnkr.co/edit/mAfkQ2DjbCdtFW3oAhBc?p=preview

if (prevValue != nextValue) {
    ctrl.$viewValue = nextValue;
    ctrl.$render();
}

if (cursorIndex == 4 || cursorIndex == 8) {
    cursorIndex = cursorIndex + 1;
}

var valid = phoneNumberRegex.test(nextValue);
ctrl.$setValidity('invalidFormat', valid);
domElement.setSelectionRange(cursorIndex, cursorIndex);


return nextValue;

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Unable to designate the drop-down option as the default selection

Can anyone help me with setting a default drop-down value using JavaScript? I have been struggling to achieve this. You can find my code on jsFiddle <div ng-controller="csrClrt"> <div ng:repeat="(key, item) in items track by $index"> ...

Utilizing JavaScript to Extract JSON Information from Knockout.js

Incorporating knockout into my project has been a great help as I retrieve JSON objects using Ajax. One question that arises is how to effectively utilize this data in my custom JavaScript code: After receiving the mapped item from the ajax call, here is ...

The functionality of OnPress for React Native Google Places Autocomplete is hindered by its surrounding parent components

I'm currently implementing the react-native-google-places-autocomplete library in my React Native application. However, I've encountered an issue when trying to select an address from the suggested list provided by Google. Whenever I click on a s ...

Picture disappearing following the refresh of an AJAX iframe

Currently, I am developing a profile system where the user's profile is displayed in an iframe that reloads when the form submit button is clicked. The content updates successfully upon reloading, but there is an issue with images not displaying after ...

Creating Highcharts series with dynamic addition of minimum and maximum values

I am currently working with a Highcharts chart that includes multiple tabs allowing users to display different data on the graph. I am dynamically adding series for each of these data points, which has been functioning well. However, I have encountered an ...

Having trouble with implementing a 64-bit bitwise AND operation in JavaScript?

I've been attempting to perform a bitwise AND operation on long numbers using Javascript. Despite trying the solutions provided at (How to do bitwise AND in javascript on variables that are longer than 32 bit?), none of them have been accurate for the ...

In Vue.js, utilize a contenteditable div to dynamically add an HTML element and bind it with v-model

Below is the HTML code I have written. <div id="app"> <button @click="renderHtml">Click to append html</button> <div class="flex"> <div class="message" @input="fakeVmodel" v-html="html" contenteditable="true">< ...

Error encountered while running a mounted hook in Vue.js that was not properly handled

I have created a To Do List app where users can add tasks using a button. Each new task is added to the list with a checkbox and delete button next to it. I want to save all the values and checked information on the page (store it) whenever the page is ref ...

There was an error: "Uncaught TypeError - onPageChange function is not defined for the DataGrid component in Material

I'm struggling to integrate a DataGrid component into my application. While the table renders correctly with the code provided, I encounter an error when clicking on the next page icon - react-dom.development.js:327 Uncaught TypeError: onPageChange is ...

Dealing with issues related to AngularJS auto-tab functionality

I implemented the code below to enable "auto tab" functionality with AngularJS, which automatically shifts focus to the "Title" textbox after the maximum length is reached in the "Name" textbox: var app = angular.module('plunker', []); app.dire ...

What is the main object used in a module in Node.js for global execution?

Node.js operates on the concept of local scope for each module, meaning variables defined within a module do not automatically become global unless explicitly exported. One question that arises is where a variable declared in a module file belongs in term ...

The default locale for momentJS is set to zh-tw and I'm having trouble changing it

Currently, I am incorporating the momentJS library into my Angular application by pulling it from a CDN: <script src="https://cdnjs.cloudflare.com/ajax/libs/moment.js/2.10.3/moment.min.js"></script> Although the default locale should be Engli ...

What is the best way to insert distinct values into an array in mongoDB?

I have a table of likes, and within that table, there is an array called videoLikes. I want to store the userData of users who have liked the video. However, when I attempt to add an object with a userId field to that array, I end up with duplicate data. S ...

Dynamic value updates using jQuery input type formulas

I need help with a form that has two inputs: The first input allows the user to enter an amount, such as 1000. The second input is read-only and should display the value of the first input plus 1%. For example, if the user types in 1000 in the first fie ...

Generating a text input field with multiple lines

<!DOCTYPE html> <html> <body> <p>Press the button to generate a File Upload Button.</p> <button onclick="myFunction()">Click here</button> <script> function myFunction() { var x = document.createElemen ...

Ensuring the consistency of form fields using AngularJS

Using Angular 1.5.11 I am currently working on an HTML form that contains multiple fields, such as : <div ng-app="validationApp" ng-controller="mainController"> <div class="container"> <div class="ro ...

The button colors in Material Ui do not update properly after switching themes

React Material UI is being utilized in this project. Although the theme is being overridden, the colors of buttons and inputs remain unchanged. Here is how the Material UI theme is created in theme.js // @flow import { createMuiTheme } from '@materi ...

Adding or removing a class using Jquery based on the condition of form validation

I am facing a problem with the following code that adds and removes classes to bring the next stage of the form. The form progresses step by step where certain fields need to be filled before validation on the next button, followed by filling other fields. ...

Can you provide the specific URL for a Metacafe video to stream within a div container?

Could anyone assist me in finding the "Direct Url" to play metacafe videos within a div element? ...

Access to the Express Node.js server is restricted to the machine that is currently hosting the server

I am facing a beginner issue with using express. I am on Ubuntu 14.04 and created a new directory where I ran "express" in the terminal to set up a project template. Following that, I ran "npm install" to install the dependencies. I then made changes to &a ...