-
Notifications
You must be signed in to change notification settings - Fork 3.4k
md-input-container: Password label not floating with Chrome password-manager auto-fill #1376
Comments
Pretty sure this is due to a bug in Chrome where password autofill doesn't trigger a change on inputs. Not sure there's much we can do about it until it gets resolved. |
I know this is closed, but this has been a Chrome bug for some time and it may not be resolved for a while for all I know. So, I think, in the spirit of finding some solution as a workaround, this might be useful to people: document.querySelector("input[type=password]").value = " ";
document.querySelector("input[type=password]").value = "";
document.querySelector("input[type=password]").blur() This clears an autocomplete value, so there is some drawback to this approach. However, it looks nicer. You might also be able to use |
Should be fixed in #master with SHA a64291b |
Problem seems to persist on Chrome (v43). I've updated the test repo/site since it returned 404, but should be up now again. Will test the workaround later. |
I don't think we are out of the woods just yet, even given a64291b. I tried a few things to determine this. I:
|
@Splaktar - can you investigate this? |
Another point: the bug appears to have an intermittent nature. I can refresh @SebiH's repo/site and sometimes see the issue and sometimes not see the issue. Here is my screenshot: |
@morrissinger Seems to be related to keyboard events, possibly? On my machine, when refreshing via navigation or clicking the reload button with the mouse, the password label will not position itself correctly. When refreshing with F5, it works as expected. |
This is because of this weird Chrome behavior: |
As @SebiH stated in his last comment, this does have some interaction with exactly how the page is refreshed.
Just pressing any key after reloading the page w/ a problem causes the input to float the text properly. Based on the two Chrome bugs referenced in this issue plus an additional duplicate Chrome bug (https://code.google.com/p/chromium/issues/detail?id=398805), this appears to be Working as Intended in Chrome. There are hacks available. TBosch came up with https://github.com/tbosch/autofill-event just for this kind of issue. Unfortunately, I was not able to get that to work for me with the latest Angular about 9 months ago. I was able to solve this in one project for Firefox by using a But this hack does not appear to work for Chrome due to the above mentioned bugs related to Chrome AutoFill. The ngModel is never updated with the value from AutoFill until the user interacts with the page in some way. Also as for the reason that the Placeholder text does not behave properly, this is related to the fact that |
Same issue with using It doesn't actually use the browser's placeholder feature. It just adds it as a label with float feature enabled via @alirezamirian suggested using |
md-no-float doesn't appear to fix the label issue with password fields. Using Angular Materials v0.10.0 |
After click on any Element, also the body - the password field regonized a change, and the input moved to top. I have tried to trigger the click event, unfortunately without success.
Does anyone have any idea why this is a failure? |
@webdesignberlin Yes, Chrome browser is purposely keeping the value from being given to the element until the user interacts with the page. This is done for security reasons. They only make it look like the value has been entered, but they don't actually pass the value to the element until interaction happens. They have patched up all of the hacks to get around this (like your example) that I have been able to find. I tried at least 10 different approaches without any luck. |
@Splaktar That's not so great. Thanks for the information. Safety first. The only pity is that we live in a world where we have to pay attention to such things. |
@sjlynch you should use it as class on label. |
God I wish there was a way to disable that stupid autofill completely. Along with it's annoying yellow background. |
Status: need more discussion about how to address this |
@alirezamirian Thanks, that fixed it and it's a pretty acceptable solution. |
Setting focus to the password field seems to work as well (with some 1s delay): angular.element('#password').focus(); Edit: actually it seems to help sometimes, sometimes with delay, sometimes not at all. Might work with tuning $timeouts or something but meh... |
same problem for me :( |
@Frank3K $provide.decorator('mdInputContainerDirective', function ($mdTheming, $delegate, $interval) { var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1; var directive = $delegate[0]; directive.compile = function () { return { post: function ($scope, element, attr, ctrl) { $mdTheming(element); if (is_chrome && ctrl.input && ctrl.input.length && ctrl.input[0].type === 'password') { var count = 0; var interval = $interval(function () { if (count > 10) { $interval.cancel(interval); } if (ctrl.input.parent()[0].querySelector('input:-webkit-autofill')) { ctrl.element.addClass('md-input-has-value'); $interval.cancel(interval); } count++; }, 25); } } }; }; return $delegate; }); |
Please note that Microsoft Edge also has |
Isnt the autofill problem is a chrome only issue? Anyway I will check it tomorrow at work on edge too. Please let us know if you find anything. |
It is Chrome (or maybe Webkit)-only. I was just pointing out that the method now also runs on Microsoft Edge, where it is not needed. |
I simplified the workaround:
|
Thx for sharing :)
|
The workaround works pretty fine, but there are some issues:
So I changed the code a little to make it more reliable and added a new (function(angular){
"use strict";
var MAX_TRIES = 5;
var TRY_INTERVAL = 100;
angular.module("angular-chrome-autofill-fix", [])
.directive('mdInputContainer', mdInputContainerDirective)
.directive("required", requiredDirective);
function requiredDirective($interval, $log) {
return {
priority: 100,
require: "?ngModel",
link: linkFn
};
function linkFn(scope, elem, attrs, ngModel) {
var originalValidator = ngModel.$validators.required;
ngModel.$validators.required = validator;
// try validating until
var tries = 0;
var timer = $interval(function () {
tries++;
if (tries > MAX_TRIES) {
$interval.cancel(timer);
}
ngModel.$validate();
}, TRY_INTERVAL);
function validator(modelValue, viewValue) {
if (isChrome() && elem.is("input[type=password]:-webkit-autofill")) {
$log.info("bypassing required validator because of Chrome auto-filling");
$interval.cancel(timer);
return true;
}
return originalValidator(modelValue, viewValue);
}
}
}
function mdInputContainerDirective($interval) {
return {
restrict: "E",
link: linkFn
};
function linkFn($scope, elem) {
if (isChrome()) {
var tries = 0;
var timer = $interval(function () {
tries++;
if (tries > MAX_TRIES) {
$interval.cancel(timer);
}
if (elem[0].querySelector('input[type=password]:-webkit-autofill')) {
elem.addClass('md-input-has-value');
$interval.cancel(timer);
}
}, TRY_INTERVAL);
}
}
}
function isChrome(){
return navigator.userAgent.match(/chrome/i) && !navigator.userAgent.match(/edge/i);
}
})(angular); |
Can there be a simple fix for this soon? |
@camden-kid the project angular-chrome-autofill-fix mentioned just above your comment seems to work fine for me. Give it a try... |
still all those fixes over fixes.. just take care of it framework wise already... |
To delete the autofill password go to chrome://settings/passwords search the desired url you wish to avoid autofill and click the little x to the right of the stored password. That's the chrome way to fix it. None of those directives worked. Fortunately @antoinebrault simple adjustment putting label under input and adding this simple css line to your custom css file that should be loaded under the angular-material styles in index. HTML: <md-input-container>
<input type="password" ng-model="password" />
<label>Password</label>
</md-input-container> CSS: .md-input[type=password]:-webkit-autofill ~ label:not(.md-no-float) {
transform: translate3d(0, 6px, 0) scale(0.75);
transition: transform cubic-bezier(0.25, 0.8, 0.25, 1) 0.4s, width cubic-bezier(0.25, 0.8, 0.25, 1) 0.4s;
width: ~"calc((100% - 18px) / 0.75)";
color: rgba(0,0,0,0.54);
} From what I can tell there are two classes that should be added dynamically if there is an autofill value in the input one class |
This is very easy solution with pure CSS only. Put both Label as well as placeholder and play with the CSS as below: HTML:<md-input-container >
<label>Password</label>
<input ng-model="vm.password" placeholder="Password" id="password" name="password" type="password" required>
</md-input-container> CSS:.md-input-has-placeholder input.ng-empty::-webkit-input-placeholder{ opacity: 0;}
.md-input-invalid input.ng-empty::-webkit-input-placeholder{ opacity: 1;}
.md-input-invalid label{ display: none;}
.md-input-focused label{ display: block;}
.md-input-invalid.md-input-focused input.ng-empty::-webkit-input-placeholder{ opacity: 0;}
.md-input-invalid input.ng-empty::-webkit-input-placeholder{ opacity: 1;}
.md-input-focused input::-moz-placeholder{ opacity: 0;}
@-moz-document url-prefix() { .md-input-has-placeholder label{ display: none;}}
.md-input-has-placeholder.md-input-focused label,.md-input-has-placeholder.md-input-has-value label{ display: block;}
md-input-container.md-input-focused ::-webkit-input-placeholder:not(.md-no-float),md-input-container.md-input-has-placeholder ::-webkit-input-placeholder:not(.md-no-float), md-input-container.md-input-has-value ::-webkit-input-placeholder:not(.md-no-float) {
-webkit-transform: translate3d(0, 6px, 0) scale(0.75);
transform: translate3d(0, 6px, 0) scale(0.75);}
md-input-container.md-input-focused label::-webkit-input-placeholder:not(.md-no-float), md-input-container.md-input-has-placeholder label::-webkit-input-placeholder:not(.md-no-float),md-input-container.md-input-has-value label::-webkit-input-placeholder:not(.md-no-float) {-webkit-transform: translate3d(0, 6px, 0) scale(0.75);
transform: translate3d(0, 6px, 0) scale(0.75);} |
+1 |
I use a similar method to @antoinebrault, absent the timeout. My form has an autofocus username, with html: <form ng-class="{'auto-fill-checked': checkAutoFillValues()}">
<md-input-container>
<label>Username</label>
<input name="username" required ng-model="auth.username" autofocus/>
... md-messages validation ...
</md-input-container>
<md-input-container>
<label>Password</label>
<input name="password" type="password" required ng-model="auth.password"/>
... md-messages validation ...
</md-input-container>
</form> controller: ...
$scope.checkAutoFillValues = function() {
// Check if there are auto-filled values on the page and mark them as having a value
$('input:-webkit-autofill').each(function(i, el) {
$(el).parent().addClass('md-input-has-value');
});
}
... |
@antoinebrault .input-container input:-webkit-autofill ~ label {
color: #757575;
-webkit-transform: translate(-12%, -50%) scale(0.75);
transform: translate(-12%, -50%) scale(0.75);
} Thank You. |
I had this issue with regular css floating label trick and @SayChamp saved my day :) 👍 |
Trigger resize event on page / app load also fixed this issue
|
When using the password manager in Chrome to automatically fill in username & password on two md-input-containers, the password label will not float until some action (e.g. clicking anywhere on the page) is done:
After initial page load:
![image](https://cloud.githubusercontent.com/assets/2853456/6004178/ce74da8a-aaf8-11e4-9643-c57a98632b3a.png)
After clicking anywhere:
![image](https://cloud.githubusercontent.com/assets/2853456/6004208/f44c9c20-aaf8-11e4-9fd2-e4c18901570d.png)
Reproducing this isn't very easy, since services like Plnkr or CodePen either won't trigger the password manager or the auto-fill; however this GitHub page / repository should provide an environment where it should be reproducible:
Site: http://sebih.github.io/angular-material-pwmanagerbug/
Repo: https://github.com/SebiH/angular-material-pwmanagerbug
As there isn't any password authentification, simply type in something to (hopefully) trigger Chrome's password manager, save password and use the link to go back to the login page.
One interesting thing to note is that refreshing the login page does not seem to recreate the faulty state; however navigation via links breaks the password field again.
It seems to work properly in FireFox 35. I'm using Chrome 40, but noticed it in previous versions, too.
The text was updated successfully, but these errors were encountered: