Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

forms: update required validator when input is autofilled #30616

Open
mmalerba opened this issue May 22, 2019 · 32 comments
Open

forms: update required validator when input is autofilled #30616

mmalerba opened this issue May 22, 2019 · 32 comments
Assignees
Labels
area: forms feature: under consideration Feature request for which voting has completed and the request is now under consideration forms: change detection forms: validators P5 The team acknowledges the request but does not plan to address it, it remains open for discussion type: bug/fix
Milestone

Comments

@mmalerba
Copy link
Contributor

mmalerba commented May 22, 2019

🚀 feature request

Relevant Package

This feature request is for @angular/forms

Description

The RequiredValidator does not update its validation status when an input is autofilled in Chrome. This is problematic for users who set up a required username and password input and then conditionally enable the submit button when the inputs are valid. The user sees:

  1. Page loads
  2. Inputs are autofilled with username and password
  3. Submit button is still disabled.

This issue has been filed in the past on the components repo: angular/components#3414, though the change would really have to happen in @angular/forms.

Describe the solution you'd like

@angular/cdk has an AutofillMonitor that could be moved to @angular/forms and used to detect when an input is autofilled.

Describe alternatives you've considered

It is possible to monkey patch a solution, as @kherock demonstrated on the components issue.

@cyraid
Copy link
Contributor

cyraid commented Jan 15, 2020

I came across this bug. It's terrible because it's random when it happens! Sometimes it shows up correctly, sometimes it does not. The ng-invalid and such classes are added to it, until the user clicks on the page.

@rbinsztock
Copy link

Any news on this issue ? related to : https://bugs.chromium.org/p/chromium/issues/detail?id=352527 and vuejs/vue#7058. We updated to last Angular 9.2 but the issue is still here.

@juansanluq
Copy link

Yes, the issue still there, any news about it? Thanks.

@K0ST4S
Copy link

K0ST4S commented Dec 9, 2020

Hello. The issue is still there, and none of the hacks or patches found on internet works. This is really frustrating, as form button is shown to be disabled, because validation cannot read the text written to the input fields by the browser.
Chrome version: 87

@anton-brass
Copy link

anton-brass commented Jan 20, 2021

I had a problem with FireFox 30.0 on iOS and its autocompletion-functionality for my login page.

I implemented following workaround:

export class LoginComponent implements OnInit, AfterViewInit {
  
  @ViewChild('loginFeld')
  loginFeld: ElementRef;

  @ViewChild('passwortFeld')
  passwortFeld: ElementRef;

  loginForm: FormGroup;

  ngOnInit(): void {
    this.loginForm = this.formBuilder.group({
      login: this.formBuilder.control('', Validators.required),
      passwort: this.formBuilder.control('', Validators.required),
    });
  }

  ngAfterViewInit(): void {
    setTimeout(() => this.setControlValuesFromNativeValues(), 200);
  }

  setControlValuesFromNativeValues(): void {
    this.loginForm.get('login').setValue(this.loginFeld.nativeElement.value);
    this.loginForm.get('passwort').setValue(this.passwortFeld.nativeElement.value);
  }

It takes the native values after 200ms and sets them into the reactive forms.

@angular-robot angular-robot bot added the feature: votes required Feature request which is currently still in the voting phase label Jun 5, 2021
@angular-robot
Copy link
Contributor

angular-robot bot commented Jun 5, 2021

Just a heads up that we kicked off a community voting process for your feature request. There are 20 days until the voting process ends.

Find more details about Angular's feature request process in our documentation.

@angular-robot
Copy link
Contributor

angular-robot bot commented Jun 27, 2021

Thank you for submitting your feature request! Looks like during the polling process it didn't collect a sufficient number of votes to move to the next stage.

We want to keep Angular rich and ergonomic and at the same time be mindful about its scope and learning journey. If you think your request could live outside Angular's scope, we'd encourage you to collaborate with the community on publishing it as an open source package.

You can find more details about the feature request process in our documentation.

@angular-robot angular-robot bot added the feature: insufficient votes Label to add when the not a sufficient number of votes or comments from unique authors label Jun 27, 2021
@mrmokwa
Copy link

mrmokwa commented Jun 28, 2021

Why is it marked as feature? IMO it's a bug and shouldn't need votes to fix it.

@adamdport
Copy link

adamdport commented Jul 13, 2021

I'm not sure this is isolated to Chrome. I'm having similar issues in my iOS app packaged with Cordova. My login button is disabled based on form validity, which never changes despite the password manager having filled it in. I think I'm the 20th vote so hopefully the bot chills out

@dylhunn dylhunn added type: bug/fix and removed feature: insufficient votes Label to add when the not a sufficient number of votes or comments from unique authors feature: votes required Feature request which is currently still in the voting phase labels Jul 13, 2021
@dylhunn
Copy link
Contributor

dylhunn commented Jul 13, 2021

@adamdport 21 votes is certainly plenty, I have attempted to silence the bot.

On the one hand, this is clearly a nuisance, and many apps will want this to get nice validation behavior on login controls. But on the other hand, it's possible for apps to implement on their own, in the same manner as @angular/cdk AutofillMonitor, and adding it to forms will increase bundle size for everyone, even apps without login forms.

I personally am leaning towards fixing inside the forms package, so I have pinned this on our FR triage board for further discussion at the next triage meeting.

@angular-robot angular-robot bot added the feature: under consideration Feature request for which voting has completed and the request is now under consideration label Jul 14, 2021
@adamdport
Copy link

@dylhunn I'm unable to even get the value using Angular and was forced to resort to reading nativeElement.value, so I'm not sure that this is isolated to the required validator like this issue's title suggests. I suspect it might be a zone.js issue? A couple other related posts:

ionic-team/ionic-v3#928
https://stackoverflow.com/questions/53555114/ios-autofill-data-in-login-forms-is-empty-in-cordova-application-using-angular

@dylhunn
Copy link
Contributor

dylhunn commented Jul 26, 2021

@adamdport Interesting, that does seem to suggest the issue scope is more severe that we thought. This is just a guess, but I suspect it should be the same fix -- if updateValueAndValidity is never fired, in addition to the validators not running, the model wouldn't get the new value.

I think the fix is to bring AutoFill detection into the core of the forms package, similar to how it's implemented in @angular/cdk AutofillMonitor. Unfortunately, @AndrewKushnir and I are both pretty busy right now, but perhaps this could be a good community PR request (i.e. mark it as "help wanted")? WDYT @AndrewKushnir?

@dylhunn dylhunn added forms: change detection forms: validators and removed feature Issue that requests a new feature labels Jul 26, 2021
@ngbot ngbot bot removed this from the Backlog milestone Jul 26, 2021
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Jul 26, 2021
@dylhunn
Copy link
Contributor

dylhunn commented Jul 29, 2021

We discussed this at great length in today's (Jul 29) team meeting. Here was the gist of our discussion:

  • It's currently possible to use cdk AutofillMonitor as demonstrated here, and call updateValueAndValidity on autofills.
  • While this issue can technically affect any input element, we'd only be interested in putting code like this in Forms, not the core. (We don't want to "paper over" browser idiosyncrasies in the framework core.)
  • The existing AutofillMonitor implementation is pretty hacky; it uses a fake animation and some CSS tricks. It also doesn't work in all browsers. This means it probably can't be used as-is.
  • We're not sure a clean implementation that works in all supported browsers is possible. This requires further research.
  • If a solution exists that isn't "hacky" and works in all supported browsers, we can add it to Forms.

@mmalerba
Copy link
Contributor Author

mmalerba commented Aug 1, 2021

@dylhunn Can you elaborate about it not working in all browsers? The :autofill pseudo-class seems to have support for all browsers other than IE (which we will soon drop support for): https://developer.mozilla.org/en-US/docs/Web/CSS/:autofill (I think at the time I wrote the AutofillMonitor, Chrome was the only browser with issues, so I just used the -webkit- version)

@markusmo
Copy link

We discussed this at great length in today's (Jul 29) team meeting. Here was the gist of our discussion:

  • It's currently possible to use cdk AutofillMonitor as demonstrated here, and call updateValueAndValidity on autofills.
  • While this issue can technically affect any input element, we'd only be interested in putting code like this in Forms, not the core. (We don't want to "paper over" browser idiosyncrasies in the framework core.)
  • The existing AutofillMonitor implementation is pretty hacky; it uses a fake animation and some CSS tricks. It also doesn't work in all browsers. This means it probably can't be used as-is.
  • We're not sure a clean implementation that works in all supported browsers is possible. This requires further research.
  • If a solution exists that isn't "hacky" and works in all supported browsers, we can add it to Forms.

We're using a different approach. We have our own directive which has to be set on input fields. There we listen to change event and set value to the FormControl, triggering validators that way.

@UntilDestroy()
@Directive({
	providers: [
		{
			provide: NgControl,
			useExisting: forwardRef(() => AutoFillWorkaroundDirective )
		}
	],
	selector: '[iosAutofill]'
})
export class AutoFillWorkaroundDirective implements AfterViewInit {

	constructor(private elementRef: ElementRef, private ngControl: NgControl) {}

	ngAfterViewInit(): void {
		const element: HTMLElement = this.elementRef.nativeElement;
		const input = element.querySelector('input');
		if (!input) {
			return;
		}

		fromEvent(input, 'change')
			.pipe(untilDestroyed(this), debounceTime(100))
			.subscribe(() => {
				if (this.ngControl && this.ngControl.value !== input.value) {
					this.ngControl.control?.setValue(input.value);
				}
			});
	}
}

@jessicajaniuk jessicajaniuk added the P5 The team acknowledges the request but does not plan to address it, it remains open for discussion label Dec 13, 2021
@ngbot ngbot bot modified the milestones: needsTriage, Backlog Dec 13, 2021
@mneige
Copy link

mneige commented Dec 17, 2021

Hi all! The Monkey patch solution from @kherock is coded in Angular 6, how are you fixing this issue recently? We have the issue with Chrome and Edge but not Firefox. Thank you!

@MatiasProietti
Copy link

MatiasProietti commented Dec 18, 2021

Hello. It's important to know the difference between autofill and autocomplete.

Autofill: Automatically fill the form. (the form of autofill that affects us is the one that fills the form when the user visits the webpage).
Autocomplete: Show suggestions while the user is filling the form. (filling as in typing or clicking)

Important note before reading the actual explanation: I have tested this with Chrome because it's used by almost 65% of the users, it might be different with other browsers.

Autofill

In the case of Autofill you can't do much because the data is not actually set in the input unless the user interacts with the webpage, this is why polling for values won't work.

Edit: added an stackblitz to reproduce it, you will need to use the live webpage version instead of the editor version.
editor
webpage

  1. Visit the website and register using the Register form (the one at the top).
  2. Refresh the webpage and make sure the credentials are automatically filled by chrome.
  3. You can see that the form is valid and the values are shown at the bottom.
  4. Open a new tab and without clicking or doing anything extra, manually write the webpage url. If an autocomplete is offered select it with the keyboard and not with the mouse.
  5. You can see that the values are filled but the form doesn't have any value.
  6. Click anywhere in the webpage, now the form is valid and the values are shown.

tip: you can visit the webpage a few times to make chrome offer the autocomplete.
tip2: copy and paste seems to count as user interaction so make sure you manually write the url.

You have 3 options:

  1. Disable autofill. (I'm not sure if it's entirely possible)
  2. Adapt the form to this "problem". For example: if you have a button that is disabled when the form is invalid then remove this condition and check if the form is invalid when clicking the button.
  3. Fix and use the patch by kherock and adapt your form to it. It won't be able to give you the values because they are not set in the elements but it will let you know that the form was autofilled. Following the example from the previous point: if you have a button that is disabled when the form is invalid then add a condition that if the values were autofilled then the button is enabled.

I would recommend option 2.
Option 1 might frustrate some users and option 3 is not worth the trouble as you won't be able to tell if the autofilled value is correct because you don't have access to the values and you would also have to set the autofilled value to false when the user modifies the data in the form. The implementation is not bulletproof, it might not work in the future and it might not work on some browsers. It will be a real headache to maintain that.

Autocomplete

In this case a normal form implementation should work just fine because the user already interacted with the form.

MatiasProietti added a commit to MatiasProietti/yet-another-angular-boilerplate that referenced this issue Dec 18, 2021
It was placebo effect, it still happens on chrome.
Adapted the code to this problem.

See angular/angular#30616 (comment)
@f1ght4fun
Copy link

So is there any solution or any working hack for ionic6. My ion-inputs are staying empty and form is not updated until touch aka focus happens on the one of the fields

@djwagner-cbc
Copy link

I modified @markusmo code and it seems to work well.

@Directive({
  selector: '[appAutofillMonitor]'
})
export class AutofillMonitorDirective {

  constructor( private elementRef: ElementRef, private ngZone: NgZone) {}

  @HostListener('change', ['$event.target'])
  onChange(target) {
    this.ngZone.run(()=> {
      if (this.elementRef.nativeElement.value !== target.value) {
        this.elementRef.nativeElement.value = target.value;
      }
    });
  }

}

@f1ght4fun
Copy link

f1ght4fun commented Feb 23, 2022

Nothing is helping. No matter whether u have a form or u use ngModel, whether u put all these directives floating around internet posts with autofillmonitor or with directives to react on input change.
UNLESS you really tap ie focus/touch input - value does not appear.
Mind you i have everything setup - associated domains, webcredentials etc

@zsmatrix62
Copy link

any updates about this issue?

@lukhomdingi
Copy link

This is still an issue on Angular 14. Is there any kind of solution?

@RoyHP
Copy link

RoyHP commented Jun 27, 2023

Still a problem with chrome autofill, we are seeing it in production.

@Igor-Lira
Copy link

I had this problem in chrome too and I got it working with AutoFillMonitor as mentioned before.

To check if a submit button is disabled based on a required validation would be:

[disabled] = "this.form.touched ? this.form.invalid : !this.autofilled"
this._autofill.monitor(this.input).subscribe(e => this.autofilled = e.isAutofilled);

Note, this is a workaround, because I don't update the validation, and I don't have the autofilled value. But at least I get to disable properly, and when user interacts with the page (first click), validation is triggered.

@artuska
Copy link

artuska commented Jul 13, 2023

This issue still exists at July 2023. None of the workarounds above work. @markusmo @djwagner-cbc your solutions just does not work.

Everything works only and only after the interaction with the page, e.g. by clicking somewhere on a page.

@MrHOY
Copy link

MrHOY commented Jan 4, 2024

Any news? Jan 2024

@PRR24
Copy link

PRR24 commented Jan 15, 2024

I'm not fully convinced it is Angular issue at all. If I load a page that Chrome autofills, select the input from dev console then $0.value is '' up until I press Enter after which it changes to the value prefilled by Chrome and also the app reacts expectedly.

@firegreen
Copy link

I don't know if it's a good practice but I use a workaround to tackle this problem, active focus in code

    var inputs = this.document.getElementsByTagName("input");
    for (var i = 0; i < inputs.length; i++) {
      inputs.item(i)!.focus();
    }
    inputs.item(0)!.focus();

Values are available after fields lose focus

@caboodal
Copy link

Amazing that this issue has been around for at least 6/7 years and still no fix!

@playboxdesign
Copy link

Now don't shoot me because we have a very big project, I am learning Angular and I may be missing the fact we have added a large import ie cdk, as someone says above can increase your project size, if anyone wants to update me why people don't like cdk that would be interesting.

As, to resolve this autofill submit button issue i used this:

ngAfterViewInit(){
setTimeout(() => {
if (this.userName.nativeElement.classList.contains('cdk-text-field-autofilled')) {
this.notAutofilled = false;
}
else{console.log("Not Autofilled");}
}, 500);
}

with this on the button

[disabled]="(loginForm.invalid || loggingIn) && notAutofilled"

Is this a case that we have cdk so class 'cdk-text-field-autofilled' in our current project so I could hop on it and what you are all discussing is how to resolve this in forms when you aren't using excess modules etc.

As I say I'm learning, so be kind :)

@dedalusMohantyMa
Copy link

I'm not fully convinced it is Angular issue at all. If I load a page that Chrome autofills, select the input from dev console then $0.value is '' up until I press Enter after which it changes to the value prefilled by Chrome and also the app reacts expectedly.

Don't go down this rabbithole ... I already had a look at this and there hass been also a bug opened at Chrome, they closed it with the notion, that it is a Apple issue. Apple themselves pointed to Google and their implementation and also closed that ...

@stoneLeaf
Copy link
Contributor

I had this problem in chrome too and I got it working with AutoFillMonitor as mentioned before.

To check if a submit button is disabled based on a required validation would be:

[disabled] = "this.form.touched ? this.form.invalid : !this.autofilled"
this._autofill.monitor(this.input).subscribe(e => this.autofilled = e.isAutofilled);

Note, this is a workaround, because I don't update the validation, and I don't have the autofilled value. But at least I get to disable properly, and when user interacts with the page (first click), validation is triggered.

For disabling/enabling the submit button, using AutoFillMonitor is a perfectly satisfying and clean solution.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area: forms feature: under consideration Feature request for which voting has completed and the request is now under consideration forms: change detection forms: validators P5 The team acknowledges the request but does not plan to address it, it remains open for discussion type: bug/fix
Projects
None yet
Development

No branches or pull requests