AngularJS浏览器通过使用指令自动填充解决方法

luc*_*ssp 110 javascript mvvm angularjs

在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);
        }
    };
}]);
Run Code Online (Sandbox Code Playgroud)

问题是ngModel.$setViewValue(element.val());不会根据element.val()返回的值更改模型和视图.我怎么能做到这一点?

Ben*_*esh 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);
      }
   }
});
Run Code Online (Sandbox Code Playgroud)
<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>
Run Code Online (Sandbox Code Playgroud)

我想你只需要简化一下你的方法.我绝对推荐的一件事是检查ngModel.$pristine并确保你没有覆盖一些不良用户的输入.此外,3秒可能太长.你不应该在$ timeout,BTW中调用$ apply(),它应该自动为你排队$摘要.

真正的问题:您的浏览器是否会将Angular击败执行?我的浏览器怎么样?

这可能是一场无法取胜的战争,这就是为什么Angular(或Knockout)无法轻易解决的原因.在指令初始执行时,无法保证输入中的数据状态.甚至在Angular初始化的时候......所以这是一个棘手的问题需要解决.


bek*_*kos 35

您不必使用$timeout或类似的任何东西.您可以使用事件系统.

我认为它更像是Angularish并且不依赖于jQuery或自定义事件捕获.

例如,在您的提交处理程序上:

$scope.doLogin = function() {
    $scope.$broadcast("autofill:update");

    // Continue with the login.....
};
Run Code Online (Sandbox Code Playgroud)

然后你可以得到这样的autofill指令:

.directive("autofill", function () {
    return {
        require: "ngModel",
        link: function (scope, element, attrs, ngModel) {
            scope.$on("autofill:update", function() {
                ngModel.$setViewValue(element.val());
            });
        }
    }
});
Run Code Online (Sandbox Code Playgroud)

最后,您的HTML将如下:

<input type="text" name="username" ng-model="user.id" autofill="autofill"/>
Run Code Online (Sandbox Code Playgroud)

  • 在我的情况下,输入为空时,提交按钮被禁用. (14认同)
  • 你有没有遇到麻烦,因为它是异步的?在复制事件之前,服务器的登录调用已经离开,并且指令有时间更新范围? (4认同)

Eze*_*tor 35

这是一个远比其他解决方案更难以解决的解决方案,并且在语义上是合理的AngularJS:http://victorblog.com/2014/01/12/fixing-autocomplete-autofill-on-angularjs-form-submit/

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 autofilled 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);
    }
  };
});
Run Code Online (Sandbox Code Playgroud)

然后,您只需将指令附加到表单:

<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>
Run Code Online (Sandbox Code Playgroud)

  • 这个工作.我们尝试了上述大部分内容而没有任何结果.谢谢!!!结果在https://mobbr.com上 (2认同)
  • 现在已经是 2018 年了,这仍然是解决办法。谢谢以西结! (2认同)

OZ_*_*OZ_ 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);
                   }
               };
});
Run Code Online (Sandbox Code Playgroud)


ors*_*zky 10

不需要再破解了!当浏览器更改表单字段而不触发更改事件时,Angular dev tbosch创建了一个触发更改事件的polyfill:

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

目前他们不会将此构建到Angular代码中,因为这是浏览器的错误修复,也可以在没有Angular的情况下工作(例如,对于普通的jQuery应用程序).

"polyfill将检查文档加载的变化以及何时保留输入(仅以相同的形式).但是,如果需要,可以手动触发检查.

该项目具有单元测试和半自动测试,因此我们最终可以收集所有不同的用例以及所需的浏览器设置.

请注意:此polyfill适用于简单的AngularJS应用程序,使用AngularJS/jQuery应用程序,但也适用于不使用Angular的普通jQuery应用程序."

它可以安装:

bower install autofill-event --save
Run Code Online (Sandbox Code Playgroud)

在页面中的jQuery或Angular autofill-event.js 之后添加脚本.

这将执行以下操作:

  • 在DOMContentLoaded之后:检查所有输入字段
  • 剩下一个字段:检查相同表单中的所有其他字段

API(手动触发检查):

  • $el.checkAndTriggerAutoFillEvent():对给定jQuery/jQLite元素中的所有DOM元素执行检查.

这个怎么运作

  1. 记住用户对输入元素的所有更改(侦听更改事件)以及JavaScript(通过拦截jQuery/jQLite元素的$ el.val()).该更改的值存储在私有属性中的元素上.

  2. 检查元素是否为自动填充:将元素的当前值与记忆值进行比较.如果不同,则触发更改事件.

依赖

AngularJS或jQuery(与其中一个或两个一起工作)

github页面上的更多信息和来源.

可以在此处阅读 Github上的原始Angular问题#1460 .

  • 这对我的案例不起作用.checkAndTriggerAutoFillEvent()被触发并生成事件,但AngularJS从不更新其模型并认为字段为空. (2认同)

gor*_*ate 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();
        }
    }
}]);
Run Code Online (Sandbox Code Playgroud)

  • +1好的解决方案,类似于我提出的.我建议的唯一补充是在更改之前首先检查模型是否为'$ pristine`,然后在更改之后保持它为'$ pristine`状态.否则你会发现,如果一个表单没有加载自动填充数据,上面的指令仍会更新模型,然后使其变脏,即使表单控件仍然被认为是不受影响的.例如,使用您的指令.我已经注释掉了我要添加的代码:http://jsfiddle.net/OACDesigns/L8Sja/4/ (4认同)