111

AngularJS でフォ​​ームを送信し、ブラウザのパスワード記憶機能を使用し、その後のログイン試行でブラウザにログイン フォームにユーザー名とパスワードを入力させると、$scopeモデルは自動入力に基づいて変更されません。

私が見つけた唯一の汚いハックは、次のディレクティブを使用することです。

app.directive("xsInputSync", ["$timeout" , function($timeout) {
    return {
        restrict : "A",
        require: "?ngModel",
        link : function(scope, element, attrs, ngModel) {
            $timeout(function() {
                if (ngModel.$viewValue && ngModel.$viewValue !== element.val()) {
                    scope.apply(function() {
                        ngModel.$setViewValue(element.val());
                    });
                }
                console.log(scope);
                console.log(ngModel.$name);
                console.log(scope[ngModel.$name]);
            }, 3000);
        }
    };
}]);

問題は、返された値ngModel.$setViewValue(element.val());に基づいてモデルもビューも変更されないことです。element.val()どうすればそれを達成できますか?

4

23 に答える 23

45

どうやらこれはAngularの既知の問題であり、現在オープンです

あなたが試みているようなある種の回避策以外に、ここで何ができるかわかりません。あなたは正しい軌道に乗っているようです。ブラウザにあなたのプランクのパスワードを記憶させることができなかったので、これが機能するかどうかはわかりませんが、見てください:

app.directive('autoFillSync', function($timeout) {
   return {
      require: 'ngModel',
      link: function(scope, elem, attrs, ngModel) {
          var origVal = elem.val();
          $timeout(function () {
              var newVal = elem.val();
              if(ngModel.$pristine && origVal !== newVal) {
                  ngModel.$setViewValue(newVal);
              }
          }, 500);
      }
   }
});
<form name="myForm" ng-submit="login()">
   <label for="username">Username</label>
   <input type="text" id="username" name="username" ng-model="username" auto-fill-sync/><br/>
   <label for="password">Password</label>
   <input type="password" id="password" name="password" ng-model="password" auto-fill-sync/><br/>
   <button type="submit">Login</button>
</form>

アプローチを少し単純化する必要があると思います。私が絶対にお勧めすることの 1 つはngModel.$pristine、不適切なユーザーの入力を上書きしていないかどうかを確認することです。また、3 秒では長すぎる可能性があります。$apply() を $timeout で呼び出す必要はありませんが、$digest を自動的にキューに入れる必要があります。

本当の問題: あなたのブラウザーは Angular に勝てますか? 私のブラウザはどうですか?

これはおそらく勝てない戦争であり、それが Angular (または Knockout) が容易に解決できなかった理由です。ディレクティブの初回実行時の入力データの状態は保証されません。Angular の初期化時でさえありません....だから、解決するのは難しい問題です。

于 2013-02-19T20:25:50.803 に答える
10

汚いコードです。このコードを使用する前に、問題https://github.com/angular/angular.js/issues/1460#issuecomment-18572604が修正されているかどうかを確認してください。このディレクティブは、送信前だけでなく、フィールドが入力されたときにイベントをトリガーします (送信前に入力を処理する必要がある場合に必要です)。

 .directive('autoFillableField', function() {
    return {
                   restrict: "A",
                   require: "?ngModel",
                   link: function(scope, element, attrs, ngModel) {
                       setInterval(function() {
                           var prev_val = '';
                           if (!angular.isUndefined(attrs.xAutoFillPrevVal)) {
                               prev_val = attrs.xAutoFillPrevVal;
                           }
                           if (element.val()!=prev_val) {
                               if (!angular.isUndefined(ngModel)) {
                                   if (!(element.val()=='' && ngModel.$pristine)) {
                                       attrs.xAutoFillPrevVal = element.val();
                                       scope.$apply(function() {
                                           ngModel.$setViewValue(element.val());
                                       });
                                   }
                               }
                               else {
                                   element.trigger('input');
                                   element.trigger('change');
                                   element.trigger('keyup');
                                   attrs.xAutoFillPrevVal = element.val();
                               }
                           }
                       }, 300);
                   }
               };
});
于 2013-05-28T20:33:28.227 に答える
5

明確なまっすぐな解決策のようです。jQuery は必要ありません。

アップデート:

  • モデル値が実際の入力値と等しくない場合にのみ、モデルが更新されます。
  • チェックは最初の自動入力で停止しません。たとえば、別のアカウントを使用したい場合。

app.directive('autofillable', ['$timeout', function ($timeout) {
    return {
        scope: true,
        require: 'ngModel',
        link: function (scope, elem, attrs, ctrl) {
            scope.check = function(){
                var val = elem[0].value;
                if(ctrl.$viewValue !== val){
                    ctrl.$setViewValue(val)
                }
                $timeout(scope.check, 300);
            };
            scope.check();
        }
    }
}]);
于 2013-11-22T16:03:06.540 に答える
3

これはjQueryの方法です:

$(window).load(function() {
   // updates autofilled fields
   window.setTimeout(function() {
     $('input[ng-model]').trigger('input');
   }, 100);
 });

これはAngularの方法です:

 app.directive('autofill', ['$timeout', function ($timeout) {
    return {
        scope: true,
        require: 'ngModel',
        link: function (scope, elem, attrs, ctrl) {
            $timeout(function(){
                $(elem[0]).trigger('input');
                // elem.trigger('input'); try this if above don't work
            }, 200)
        }
    }
}]);

HTML

<input type="number" autofill /> 
于 2013-10-22T04:46:04.893 に答える
1

送信ハンドラーでのワンライナー回避策 (jQuery が必要):

if (!$scope.model) $scope.model = $('#input_field').val();
于 2013-10-18T16:21:37.047 に答える
1

これは、それほどハックではありませんが、コントローラーに追加のコードが必要な別の回避策です。

HTML:

<form ng-submit="submitForm()" ng-controller="FormController">
    <input type="text" ng-model="username" autocomplete-username>
    <input type="submit">
</form>

ディレクティブ (CoffeeScript):

directives.directive 'autocompleteUsername', ->
    return (scope, element) ->
        scope.getUsername = ->
            element.val()

コントローラ:

controllers.controller 'FormController', [->
    $scope.submitForm = ->
        username = $scope.getUsername?() ? $scope.username
        # HTTP stuff...
]
于 2013-06-19T19:11:22.433 に答える
1

これは、送信ボタンの無効化/有効化を含む、Angular のすべての検証が設計どおりに機能することを可能にする唯一の解決策です。bower と 1 つのスクリプト タグでインストールします。バジンガ!

https://github.com/tbosch/autofill-event

于 2014-03-24T01:43:48.013 に答える
1

タイムアウト機能を使用する代わりに、モデル値を変更するとうまくいきました。

これが私のコードです:

module.directive('autoFill', [ function() {
    return {
        require: 'ngModel',
        link:function(scope, element, attr, ngModel) {
            var origVal = element.val();
            if(origVal){
                ngModel.$modelValue = ngModel.$modelValue || origVal;
            }
        }
    };
}]);
于 2014-08-21T00:14:47.883 に答える
0

私のユースケースでは、これらのソリューションはどれも機能しませんでした。変更を監視するために ng-change を使用するフォーム フィールドがいくつかあります。$watch自動入力によってトリガーされないため、使用しても役に立ちません。送信ボタンがないため、一部のソリューションを実行する簡単な方法がなく、インターバルを使用してもうまくいきませんでした。

私は最終的に自動入力を無効にしました - 理想的ではありませんが、ユーザーの混乱ははるかに少なくなりました.

<input readonly onfocus="this.removeAttribute('readonly');">

ここで答えを見つけました

于 2016-06-12T19:06:42.630 に答える
0

ディレクティブなしのソリューション:

.run(["$window", "$rootElement", "$timeout", function($window, $rootElement, $timeout){

        var event =$window.document.createEvent("HTMLEvents");
        event.initEvent("change", true, true);

        $timeout(function(){

            Array.apply(null, $rootElement.find("input")).forEach(function(item){
                if (item.value.length) {
                    item.$$currentValue = item.value;
                    item.dispatchEvent(event);
                }
            });

        }, 500);
    }])
于 2014-04-10T11:13:53.343 に答える
0

この回答へのマイナーな変更 ( https://stackoverflow.com/a/14966711/3443828 ): $timeout の代わりに $interval を使用して、ブラウザーを競合させる必要がないようにします。

mod.directive('autoFillSync', function($interval) {
    function link(scope, element, attrs, ngModel) {
        var origVal = element.val();
        var refresh = $interval(function() {
          if (!ngModel.$pristine) {
            $interval.cancel(refresh);
          }else{
            var newVal = element.val();
            if (origVal !== newVal) {
              ngModel.$setViewValue(newVal);
              $interval.cancel(refresh);
            }
          }
        }, 100);
    }

    return {
      require: 'ngModel',
      link: link
    }
  });
于 2014-03-20T20:34:22.507 に答える
0

送信時に $setValue(val()) を強制します: (これはjQueryなしで機能します)

   var ValidSubmit = ['$parse', function ($parse) {
    return {
        compile: function compile(tElement, tAttrs, transclude) {
            return {
                post: function postLink(scope, element, iAttrs, controller) {
                    var form = element.controller('form');
                    form.$submitted = false;
                    var fn = $parse(iAttrs.validSubmit);
                    element.on('submit', function(event) {
                        scope.$apply(function() {
                            var inputs = element.find('input');
                            for(var i=0; i < inputs.length; i++) {
                                var ele = inputs.eq(i);
                                var field = form[inputs[i].name];
                                field.$setViewValue(ele.val());
                            }
                            element.addClass('ng-submitted');
                            form.$submitted = true;
                            if(form.$valid) {
                                fn(scope, {$event:event});
                            }
                        });
                    });
                    scope.$watch(function() { return form.$valid}, function(isValid) {
                        if(form.$submitted == false) return;
                        if(isValid) {
                            element.removeClass('has-error').addClass('has-success');
                        } else {
                            element.removeClass('has-success');
                            element.addClass('has-error');
                        }
                    });
                }
            }
        }
    }
}]
app.directive('validSubmit', ValidSubmit);
于 2013-10-16T17:45:57.327 に答える
0

私はAngularjsを初めて使用しますが、その問題に対する簡単な解決策を見つけました=> Angularに式を強制的に再評価させます...変更することで! (もちろん、初期状態に戻すには初期値を覚えておく必要があります) フォームを送信するためのコントローラー関数での処理方法は次のとおりです。

    $scope.submit = function () {
                var oldpassword = $scope.password;
                $scope.password = '';
                $scope.password = oldpassword;
//rest of your code of the submit function goes here...

もちろん、パスワード入力に入力された値は、ユーザーではなくウィンドウによって設定されています。

于 2014-02-05T09:17:20.533 に答える
0

これは、Firefox と Chrome の両方でテストしたすべてのケースで機能する簡単な修正です。一番上の回答(タイムアウト付きのディレクティブ)で問題が発生したことに注意してください-

  • ブラウザの戻る/進むボタン、ページ読み込みイベントを再起動しない (修正が適用されないため)
  • ページのロード後しばらくして資格情報のロード。たとえば、Firefox では、ログイン ボックスをダブルクリックし、保存されている資格情報から選択します。
  • 有効な入力が提供されるまでログインボタンを無効にするため、フォーム送信前に更新するソリューションが必要です

この修正は明らかに非常にばかげていてハックですが、100% の確率で機能します -

function myScope($scope, $timeout) {
    // ...
    (function autoFillFix() {
        $timeout(function() { 
            $('#username').trigger('change'); 
            $('#password').trigger('change'); 
            autoFillFix(); }, 500);                    
    })();
}
于 2014-04-24T00:27:23.027 に答える
0

これは、フォームで最終的に使用したソリューションです。

.directive('autofillSync', [ function(){
  var link = function(scope, element, attrs, ngFormCtrl){
    element.on('submit', function(event){
      if(ngFormCtrl.$dirty){
        console.log('returning as form is dirty');
        return;
      }   
      element.find('input').each(function(index, input){
        angular.element(input).trigger('input');
      }); 
    }); 
  };  
  return {
    /* negative priority to make this post link function run first */
    priority:-1,
    link: link,
    require: 'form'
  };  
}]);

そして、フォームのテンプレートは

<form autofill-sync name="user.loginForm" class="login-form" novalidate ng-submit="signIn()">
    <!-- Input fields here -->
</form>

このようにして、ng-model で持っているパーサー/フォーマッターを実行し、送信機能を透過的にすることができました。

于 2014-04-08T10:58:18.823 に答える
-1

jQuery を使用している場合は、フォームの送信時にこれを行うことができます。

HTML:

<form ng-submit="submit()">
    <input id="email" ng-model="password" required 
           type="text" placeholder="Your email">
    <input id="password" ng-model="password" required 
           type="password" placeholder="Password">
</form>

JS:

 $scope.submit = function() {
     $scope.password = $('#password').val();
}
于 2013-10-21T15:48:16.303 に答える
-1

シンプルに保ちたい場合は、JavaScriptを使用して値を取得するだけです

angular jsコントローラーで:

var ユーザー名 = document.getElementById('ユーザー名').value;

于 2014-10-04T07:17:30.870 に答える