Дилемма автокомпонентов Chrome Angularjs

У меня есть простая форма входа в систему, которая работает просто peachy, если вы не используете функцию автообновления Chrome.

Если вы начнете печатать и использовать функцию автозаполнения, и она автоматически заполняет ваш пароль, моя модель angularjs не имеет никакого значения для пароля.

Я попытался отключить автозаполнение, установив атрибут в форме autocomplete="off", но это не имеет никакого эффекта.

Как я могу: 1. Убедитесь, что я могу получить значение, если кто-то использует функцию автозаполнения Chrome? 2. Отключить функцию автообновления Chrome?

<form class="form-signin" name="form" ng-submit="login()" autocomplete="off">

        <h3>Login</h3>

        <input type="email" name="email" class="form-control" placeholder="Email address" ng-model="user.email" required autofocus>
        <input type="password" name="password" class="form-control" placeholder="Password" ng-model="user.password" required>

        <button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>

 </form>

Ответ 1

Из ссылки, добавленной в комментарий: Проблема Github

// Due to browsers issue, it impossible to detect without a timeout any changes of autofilled inputs
// https://github.com/angular/angular.js/issues/1460
// https://github.com/angular/angular.js/issues/1460#issuecomment-28662156
// Could break future Angular releases (if use `compile()` instead of `link())
// TODO support select
angular.module("app").config(["$provide", function($provide) {
    var inputDecoration = ["$delegate", "inputsWatcher", function($delegate, inputsWatcher) {
        var directive = $delegate[0];
        var link = directive.link;

        function linkDecoration(scope, element, attrs, ngModel){
            var handler;
            // By default model.$viewValue is equals to undefined
            if(attrs.type == "checkbox"){
                inputsWatcher.registerInput(handler = function(){
                    var value = element[0].checked;
                    // By default element is not checked
                    if (value && ngModel.$viewValue !== value) {
                        ngModel.$setViewValue(value);
                    }
                });
            }else if(attrs.type == "radio"){
                inputsWatcher.registerInput(handler = function(){
                    var value = attrs.value;
                    // By default element is not checked
                    if (element[0].checked && ngModel.$viewValue !== value) {
                        ngModel.$setViewValue(value);
                    }
                });
            }else{
                inputsWatcher.registerInput(handler = function(){
                    var value = element.val();
                    // By default value is an empty string
                    if ((ngModel.$viewValue !== undefined || value !== "") && ngModel.$viewValue !== value) {
                        ngModel.$setViewValue(value);
                    }
                });
            }

            scope.$on("$destroy", function(){
                inputsWatcher.unregisterInput(handler);
            });

            // Exec original `link()`
            link.apply(this, [].slice.call(arguments, 0));
        }

        // Decorate `link()` don't work for `inputDirective` (why?)
        /*
         directive.link = linkDecoration;
         */
        // So use `compile()` instead
        directive.compile = function compile(element, attrs, transclude){
            return linkDecoration;
        };
        delete directive.link;

        return $delegate;
    }];

    $provide.decorator("inputDirective", inputDecoration);
    $provide.decorator("textareaDirective", inputDecoration);
    //TODO decorate selectDirective (see binding "change" for `Single()` and `Multiple()`)
}]).factory("inputsWatcher", ["$interval", "$rootScope", function($interval, $rootScope){
    var INTERVAL_MS = 500;
    var promise;
    var handlers = [];

    function execHandlers(){
        for(var i = 0, l = handlers.length; i < l; i++){
            handlers[i]();
        }
    }

    return {
        registerInput: function registerInput(handler){
            if(handlers.push(handler) == 1){
                promise = $interval(execHandlers, INTERVAL_MS);
            }
        },
        unregisterInput: function unregisterInput(handler){
            handlers.splice(handlers.indexOf(handler), 1);
            if(handlers.length == 0){
                $interval.cancel(promise);
            }
        }
    }
}]);

Ответ 2

Как сказано здесь, https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form

Пользовательский интерфейс Google Chrome для автозаполнения запросов зависит от будет ли автозаполнение отключено на входных элементах, а также их форма. В частности, когда форма имеет автозаполнение, установленное на поле автозаполнения входного элемента не установлено, тогда, если пользователь запрашивает для предложений автозаполнения для элемента ввода, Chrome может отображать сообщение "autocomplete был отключен для этой формы". На с другой стороны, если и форма, и входной элемент имеют автозаполнение выключено, браузер не отобразит это сообщение. Для этого причине, вы должны отключить автозаполнение для каждого входа, который пользовательское автозаполнение.

Вам нужно установить autocomplete = "off" на form и input

Я не думаю, что это связано с AngularJS

Ответ 3

От: Developer.mozilla.org docs Turning_off_form_autocompletion

Если автор хотел бы предотвратить автоматическое заполнение полей пароля на страницах управления пользователями, где пользователь может указать новый пароль для кто-то другой, кроме себя, autocomplete = "new-password" должен быть но поддержка для этого не была реализована во всех браузеров.

Итак, что заставляет это работать для меня:

  • установить autocomplete = "new-password" в поле пароля
  • установить autocomplete = "off" в поле имени пользователя.

Я надеюсь, что это сработает и для вас:)

Ответ 4

У меня была такая же проблема, и я нашел очень простое решение, которое просто использует jQuery для захвата значения для submit. В моем контроллере у меня есть следующее:

$scope.username = "";
$scope.password = "";

$scope.login = function(){
    $scope.username = $("#username").val();
    $scope.password = $("#password").val();
    // Proceed as normal
};

Есть некоторые недостатки, если вам нужно выполнить проверку и т.д., но в противном случае это отлично подходит для небольших форм, подобных этому.

Ответ 5

Вы можете посмотреть значение поля электронной почты, и каждый раз, когда значение в этом поле изменяется, вы можете вызвать "изменение" -эвен в поле пароля. Эти события запускают все магии ng-модели в этом поле и обновляют модель.

module.directive("autocompleteFor", function () {
    return {
        restrict: "A",
        link: function ($scope, $element, $attrs) {
            $scope.$watch($attrs.autocompleteFor, function () {
                $element.triggerHandler("change");
            })
        }
    }
});

С помощью этой директивы вы можете обработать этот сценарий следующим образом:

<input type="email" name="email" ng-model="user.email">
<input type="password" autocomplete-for="user.email" name="password" ng-model="user.password"   required>
                       -----------------------------

Ответ 6

Чтобы отключить автозаполнение/автозаполнение от ввода, просто введите: - autocomplete = "false" вместо autocomplete = "off"!

Ответ 7

Ниже директива работала для меня. Это простое и чистое исправление. Надеюсь, что это поможет!

Ссылка: Обходной способ обозревателя браузера AngularJS с использованием директивы

Вот решение, которое намного менее хакерское, чем другие представленные решения, и семантически звучит. AngularJS: VictorBlog.com

myApp.directive('formAutofillFix', function() {
  return function(scope, elem, attrs) {
    // Fixes Chrome bug: https://groups.google.com/forum/#!topic/angular/6NlucSskQjY
    elem.prop('method', 'POST');

    // Fix autofill issues where Angular doesn't know about auto-filled inputs
    if(attrs.ngSubmit) {
      setTimeout(function() {
        elem.unbind('submit').submit(function(e) {
          e.preventDefault();
          elem.find('input, textarea, select').trigger('input').trigger('change').trigger('keydown');
          scope.$apply(attrs.ngSubmit);
        });
      }, 0);
    }
  };
});

Затем вы просто присоединяете директиву к своей форме:

<form ng-submit="submitLoginForm()" form-autofill-fix>
  <div>
    <input type="email" ng-model="email" ng-required />
    <input type="password" ng-model="password" ng-required />
    <button type="submit">Log In</button>
  </div>
</form>

Ответ 8

--- НЕ ДОЛЖНО СООТВЕТСТВУЕТ ---

Мне удалось отключить автозаполнение (достаточно странно), добавив следующее.

<form ... novalidate>
<input ... formnovalidate />

Ссылка на этот Plunker

Ответ 10

Старый вопрос, но что угодно

Я столкнулся с той же проблемой, и у меня есть небольшое "взломанное" решение. Эта проблема произошла во многих разных местах моего приложения, поэтому я создал директиву для повторного использования.

module.directive("fakeAutocomplete", [
  function () {
    return {
      restrict: "EA",
      replace: true,
      template: "<div><input/><input type=\"password\"/></div>",
      link: function (scope, elem, attrs) {
        elem.css({
          "overflow": "hidden",
          "width": "0px",
          "height": "0px"
        });
      }
    }
  }
]);

И просто добавьте

<fake-autocomplete></fake-autocomplete>

В начале вашей формы и браузер обнаружит поддельные поля как те, которые должны автозаполняться. Просто размещение display:none в полях также больше не работает, я его протестировал.

Ответ 11

В моем случае я устанавливаю свойство autocomplete = "off" в форме и вводе.

<form autocomplete="off">
   <input type="text" autocomplete="off">
</form>

Ответ 12

Это может быть гораздо более простое решение проблемы.

  • Angularjs не может "видеть" значение
  • Возьмите значение через DOM (jQuery), затем верните его в Angularjs.

`` `

angular.module('someModule').directive('chromeAutofillHack', function()
{
    return {
        require: '^ngModel',
        restrict: 'A',
        priority: 500, // set higher priority then other custom directives
        link: function(scope, element, attrs , ngModelCtrl)
        {
            ngModelCtrl.$parsers.unshift(function(email)
            {
                if (!email) { // only do this when angular think there is no value
                    email = $(element).val();
                    ngModel.$setViewValue(email);
                }
                return email;
            });
        }
    };
});

`` `