Chrome自动填充AngularJS字段错误

时间:2015-12-07 19:24:33

标签: javascript angularjs google-chrome

我正在尝试解决使用自定义Angular指令和Chrome自动填充时我注意到的错误。我已经为电话号码字段写了一个指令。该指令添加了破折号" - "到电话号码字段(因此用户在输入号码时不必添加任何破折号)。

该指令列于下面

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

            var domElement = elem[0]; // Get DOM element
            var phoneNumberRegex = new RegExp("\\d{3}\\-\\d{3}\\-\\d{4}"); // Phone number regex
            var cursorIndex; // Index where the cursor should be

            // Create a parser to alter and validate if our
            // value is a valid phone number
            ctrl.$parsers.push(function (value) {

                // If our value is non-existent, we return undefined
                // WHY?: an angular model value should be undefined if it is empty
                if (typeof value === "undefined" || value === null || value == "") {
                    ctrl.$setValidity('invalidFormat', true); // No invalid format if the value of the phone number is empty
                    return undefined;
                }

                // PARSER LOGIC
                // =compare our value to a modified value after it has
                // been transformed into a "nice" phone number. If these
                // values are different, we set the viewValue to 
                // the "nice" phone number. If these values are the same,
                // we render the viewValue (aka. "nice" phone number)
                var prevValue, nextValue;

                prevValue = value;
                nextValue = value.replace(/[\D]/gi, ""); // Strip all non-digits

                // Make the "nice" phone number
                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");
                }

                // Save the correct index where the custor should be
                // WHY?: we do this here because "ctrl.$render()" shifts
                // the cursor index to the end of the phone number
                cursorIndex = domElement.selectionStart;

                if (prevValue != nextValue) {
                    ctrl.$setViewValue(nextValue); // *Calling this function will run all functions in ctrl.$parsers!
                } else {
                    ctrl.$render(); // Render the new, "nice" phone number
                }

                // If our cursor lands on an index where a dash "-" is,
                // move it up by one
                if (cursorIndex == 4 || cursorIndex == 8) {
                    cursorIndex = cursorIndex + 1;
                }

                var valid = phoneNumberRegex.test(value); // Test the validity of our phone number
                ctrl.$setValidity('invalidFormat', valid); // Set the validity of the phone number field
                domElement.setSelectionRange(cursorIndex, cursorIndex); // Assign the cursor to the correct index

                return value; // Return the updated value
            });
        }
    }
});

当Chrome自动填充此字段时,问题就在于此。通过使用Batarang扩展(https://chrome.google.com/webstore/detail/angularjs-batarang/ighdmehidhipcmcojjgiloacoafjmpfk?hl=en),我能够看到我的页面上使用的范围值。
当我使用Chrome 自动填充我的电话号码字段,值为&#34; 1234567899&#34;时,我的$scope中的Angular电话字段值是1234567899(应该是:&#34; 123-546-7899&#34;)。

在我的指令中放置断点将使我能够在Chrome自动填充我的字段时看到该指令确实在我的浏览器中运行,但$scope.PhoneNumber字段值为1234567899,而不是123-456-7899。 简而言之,$ viewModel在自动填充时会得到正确更新,但$ modelValue不会

一旦Chrome自动填充手机字段,我是否可以编程方式更改$modelValue以反映$scope.PhoneNumber中应保留的正确值?

PLUNKR

1 个答案:

答案 0 :(得分:2)

这可以按预期工作,但这绝对令人困惑。 结论:$ setViewValue不能在解析器中调用,因为$ setViewValue本身会触发完整的$ parsers,$ validators管道直到实际的模型值。 那会发生什么? 如果值不同,则调用另一个$ setViewValue。因为管道是同步的,所以它会在第一次运行完成之前再次运行$ parsers!因此,解析器第一次运行时的返回值是实际设置给模型的值。我建议你不要在解析器中调用$ setViewValue,只需设置$ viewValue并调用$ render。

当您没有自动填充时(或简单粘贴也可以),您也可以看到问题。输入1234(单独),您将看到模型为1234,因为这是原始值。仅当输入5时,该值将为123-45,因为此时视图已经使用短划线更新。

它只是角侧的弱API。没有明确的方法来转换视图,因此人们滥用解析器。从技术上讲,我建议覆盖$ setViewValue fn,因此传递给解析器的值已经正确格式化。

更新示例: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;