web-dev-qa-db-ja.com

Angularjs Chromeオートコンプリートジレンマ

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>
38
Catfish

コメントに追加されたリンクから: Github Issue's

// Due to browsers issue, it's 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);
            }
        }
    }
}]);
21
Pauli Price

From: Developer.mozilla.org docs Turning_off_form_autocompletion

作成者が、ユーザーが自分以外のユーザーの新しいパスワードを指定できるユーザー管理ページのパスワードフィールドの自動入力を禁止する場合は、autocomplete = "new-password"を指定する必要がありますが、これはサポートされていませんまだすべてのブラウザに実装されています。

だから、それが私にとってうまくいくのは何ですか:

  • パスワードフィールドにautocomplete = "new-password"を設定します
  • ユーザー名フィールドにautocomplete = "off"を設定します。

私もそれがあなたのために働くことを願っています:)

15
ptgamr

ここで述べたように、 https://developer.mozilla.org/en-US/docs/Web/HTML/Element/form

Google ChromeオートコンプリートリクエストのUIは、入力要素とそのフォームでオートコンプリートがオフに設定されているかどうかによって異なります。特に、フォームのオートコンプリートがオフに設定され、入力が要素のオートコンプリートフィールドが設定されていない場合、ユーザーが入力要素のオートフィル候補を要求すると、Chromeはこのフォームではオートコンプリートが無効になっています。フォームと入力要素の両方でオートコンプリートがオフに設定されている場合、ブラウザはそのメッセージを表示しません。このため、カスタムのオートコンプリートを持つ各入力に対してオートコンプリートをオフに設定する必要があります。

forminputの両方でautocomplete = "off"を設定する必要があります

これはAngularJSに関連するとは思わない

11
allenhwkim

私は同じ問題を抱えていて、jQueryを使用して送信時に値を取得するだけの非常に簡単なソリューションを見つけました。私のコントローラーには次のものがあります:

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

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

検証などを行う必要がある場合はいくつかの欠点がありますが、そうでない場合はこのような小さなフォームには問題ありません。

7
Dachande663

電子メールフィールドの値を監視し、そのフィールドの値が変更されるたびに、パスワードフィールドで「変更」イベントをトリガーできます。このイベントは、そのフィールドですべてのng-modelマジックをトリガーし、モデルを更新します。

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>
                       -----------------------------
2
kfis

入力からオートコンプリート/オートフィルを無効にするには、次のように入力します。-autocomplete = "off"ではなくautocomplete = "false"!

2
Rafael Ferreira

以下のディレクティブは私のために働いた。簡単でクリーンな修正です。お役に立てば幸いです!

参照: 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>
2
FullStackDev

別の解決策は、フォーム要素を取り除き、代わりにng-formを使用することです。すべてのブラウザ干渉を無効にします

<div ng-form="yourFormName" class="form-signin" ng-submit="login()">
1

私は、ここにはまだ表示されていない別のソリューションになりました。私が見つけたものから、ユーザーがページを操作するまで、パスワード値はモデル(または場合によってはjs API)に公開されません。ログインボタンをクリックするだけで、値を利用できるようになり、ボタンのクリックハンドラーがモデルのパスワードにアクセスするのに十分早くデータバインディングが成功します。したがって、ブラウザが自動入力されたことを検出できれば、モデルがまだ更新されていなくてもログインボタンを有効にできます。そこで、Chromeが入力を自動入力したかどうかを確認する簡単なヘルパーサービスを作成しました。

utilApp.service('autoFillDetectionService', [function () {
    return {
        hasAutoFillInputs: function () {
            try{
                return !!$(':-webkit-autofill').length;
            }
            catch (x) {
                // IE gets here, it/jquery complains about an invalid pseudo-class
                return false;
            }
        }
    };
}]);

ログインコントローラから、入力フィールドが自動入力としてマークされているかどうかをチェックする間隔があり、そうであればログインボタンを有効にします。

0
bmm6o

Chrome 35.0、Firefox 30.0、angular 1.2.18(ログインページにパスワードマネージャー、自動入力、angularメソッドとリダイレクト):

ブラウザはユーザーにパスワードの保存を促すタイミングをどのように知るのですか?

0
110maor

---もう関係ない---

以下を追加することで、オートコンプリートを無効にすることができました(奇妙なことに)。

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

このPlunkerを参照

0
Cory Silva

それは問題に対するはるかに簡単な解決策かもしれません。

  1. Angularjsは値を「見る」ことができませんでした
  2. 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;
            });
        }
    };
});

`` `

0
Joel Chu

私の場合、フォームと入力でプロパティautocomplete = "off"を設定します。

<form autocomplete="off">
   <input type="text" autocomplete="off">
</form>
0
Kate.spot

古い質問ですが、何でも

私は同じ問題に遭遇し、小さな「ハック」ソリューションを手に入れました。この問題はアプリのさまざまな場所で発生したため、再利用性のディレクティブを作成しました。

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フィールドでも動作しないようです、私はそれをテストしました。

0
Louis Boux