Javascript AngularJS浏览器使用指令自动填充解决方案
在AngularJS中提交表单并使用浏览器记住密码功能时,在随后的登录尝试中,您让浏览器使用用户名和密码填写登录表单,Javascript AngularJS浏览器使用指令自动填充解决方案,javascript,mvvm,angularjs,Javascript,Mvvm,Angularjs,在AngularJS中提交表单并使用浏览器记住密码功能时,在随后的登录尝试中,您让浏览器使用用户名和密码填写登录表单,$scope模型不会根据自动填充更改 我发现的唯一肮脏的黑客行为是使用以下指令: app.directive("xsInputSync", ["$timeout" , function($timeout) { return { restrict : "A", require: "?ngModel", link : funct
$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())
不会根据元素.val()
返回的值更改模型或视图。我如何才能做到这一点?
我不确定你在这里除了做些你正在尝试的工作之外还能做些什么。看来你走对了方向。我无法让我的浏览器尝试为您的plunk记住密码,因此我不确定这是否有效,但请查看:
app.directive('autoFillSync',函数($timeout){
返回{
要求:'ngModel',
链接:功能(范围、要素、属性、ngModel){
var origVal=elem.val();
$timeout(函数(){
var newVal=elem.val();
if(ngModel.$pristine&&origVal!==newVal){
ngModel.$setViewValue(newVal);
}
}, 500);
}
}
});
用户名
密码
登录
我认为你只需要简化一下你的方法。我绝对推荐的一件事是检查ngModel.$pristine
,确保您没有覆盖一些糟糕的用户输入。另外,3秒可能太长了。您不必在$timeout中调用$apply(),顺便说一句,它应该自动为您排队等待$digest
真正的问题:你的浏览器是否会在执行上超越角度?我的浏览器呢?
这可能是一场无法取胜的战争,这就是为什么Angular(或Knockout)无法轻易解决这场战争的原因。在指令初始执行时,无法保证输入中数据的状态。甚至在Angular的初始化时都没有。。。。所以这是一个需要解决的棘手问题。脏代码,请在使用此代码之前检查问题是否已修复。 此指令在字段填充时触发事件,而不仅仅是在提交之前(如果您必须在提交之前处理输入,则有必要这样做)
这里有另一个解决方法,它不太黑客,但需要在控制器中添加一些额外的代码 HTML: 控制器:
controllers.controller 'FormController', [->
$scope.submitForm = ->
username = $scope.getUsername?() ? $scope.username
# HTTP stuff...
]
嗯,最简单的方法是模拟浏览器的行为,因此如果更改事件有问题,只需自己启动即可。简单得多 指令:
yourModule.directive('triggerChange', function($sniffer) {
return {
link : function(scope, elem, attrs) {
elem.on('click', function(){
$(attrs.triggerChange).trigger(
$sniffer.hasEvent('input') ? 'input' : 'change'
);
});
},
priority : 1
}
});
HTML:
您可以做一些修改,比如将指令放在表单上,并在表单提交时使用.dirty类对所有输入触发事件。我在提交时强制使用$setValue(val()):(这在不使用jQuery的情况下有效)
var ValidSubmit=['$parse',函数($parse){
返回{
编译:函数编译(远程通讯、tAttrs、转置){
返回{
post:功能postLink(范围、元素、iAttrs、控制器){
var form=element.controller('form');
表格.$submitted=false;
var fn=$parse(iAttrs.validSubmit);
元素。on('submit',函数(事件){
作用域$apply(函数(){
var inputs=element.find('input');
对于(变量i=0;i
提交处理程序中的一个线性解决方案(需要jQuery):
如果您使用的是jQuery,则可以在表单提交中执行此操作: HTML:
这是jQuery的方式:
$(window).load(function() {
// updates autofilled fields
window.setTimeout(function() {
$('input[ng-model]').trigger('input');
}, 100);
});
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)
}
}
}]);
这是一种有角度的方式:
$(window).load(function() {
// updates autofilled fields
window.setTimeout(function() {
$('input[ng-model]').trigger('input');
}, 100);
});
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 />
您不必使用
$timeout
或类似的方法。您可以使用事件系统
我认为它更像Angularish,不依赖于jQuery或自定义事件捕获
例如,在提交处理程序上:
$scope.doLogin=function(){
$scope.$broadcast(“自动填充:更新”);
//继续登录。。。。。
};
然后您可以有一个如下的autofill
指令:
指令(“自动填充”,函数(){
返回{
要求:“ngModel”,
链接:功能(范围、元素、属性、模型){
作用域:$on(“自动填充:更新”,函数(){
ngModel.$setViewValue(element.val());
});
}
}
});
最后,您的HTML将如下所示:
似乎是明确的直截了当的解决方案。不需要jQuery 更新:
- 仅当模型值不等于实际输入时,才更新模型 价值观
- 检查不会在第一次自动填充时停止。如果您希望使用
另一个帐户
if (!$scope.model) $scope.model = $('#input_field').val();
<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>
$scope.submit = function() { $scope.password = $('#password').val(); }
$(window).load(function() { // updates autofilled fields window.setTimeout(function() { $('input[ng-model]').trigger('input'); }, 100); });
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) } } }]);
<input type="number" autofill />
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(); } } }]);
$scope.submit = function () { var oldpassword = $scope.password; $scope.password = ''; $scope.password = oldpassword; //rest of your code of the submit function goes here...
yourapp.directive('autofill',function () { return { scope: true, require: 'ngModel', link: function (scope, elem, attrs, ctrl) { var origVal = elem.val(); if (origVal != '') { elem.trigger('input'); } } } });
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 } });
.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>
.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); }])
function myScope($scope, $timeout) { // ... (function autoFillFix() { $timeout(function() { $('#username').trigger('change'); $('#password').trigger('change'); autoFillFix(); }, 500); })(); }
app.directive('autoFillSync', function($timeout) { return { require: 'ngModel', link: function(scope, elem, attrs, model) { var origVal = elem.val(); $timeout(function () { var newVal = elem.val(); if(model.$pristine && origVal !== newVal) { model.$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>
app.directive("autofill", function () { return { require: "ngModel", link: function (scope, element, attrs, ngModel) { scope.$on("autofill:update", function() { ngModel.$setViewValue(element.val()); }); } }; });
<form name="myForm" ng-submit="login()"> <label for="username">Username</label> <input type="text" id="username" name="username" ng-model="username" autofill/><br/> <label for="password">Password</label> <input type="password" id="password" name="password" ng-model="password" autofill/><br/> <button type="submit">Login</button> </form>
app.directive('autoFill', function() { return { restrict: 'A', link: function(scope,element) { scope.submit = function(){ scope.username = element.find("#username").val(); scope.password = element.find("#password").val(); scope.login();//call a login method in your controller or write the code here itself } } }; });
<form name="myForm" auto-fill ng-submit="submit()"> <label for="username">Username</label> <input type="text" id="username" name="username" ng-model="username" /> <label for="password">Password</label> <input type="password" id="password" name="password" ng-model="password" /> <button type="submit">Login</button> </form>
module.directive('autoFill', [ function() { return { require: 'ngModel', link:function(scope, element, attr, ngModel) { var origVal = element.val(); if(origVal){ ngModel.$modelValue = ngModel.$modelValue || origVal; } } }; }]);
bower install autofill-event --save
<input readonly onfocus="this.removeAttribute('readonly');">