https://twitter.com/PentaPROgram/status/1550787703230574592
I came across that tweet and realized I had never written this up, so here is a summary of the workaround. This is a mobile Safari (WKWebView) bug, and it still has not been fixed. By the way, unless you are using Cordova/Capacitor or building your own WebView app, this bug does not affect you.
https://bugs.webkit.org/show_bug.cgi?id=226023
The explanation below uses ion-input, but from the issues it looks like plain input elements reproduce it too.
Why It Happens
When autocomplete fills the field, WebKit does not fire an input event.
How to Fix It
The change event does fire, so listen for change and pass the value through.
<ion-input #emailInput [(ngModel)]="email" type="email" name="email"></ion-input>
Suppose you have an element like that. Here is how to make it work with autocomplete. I will explain based on a basic Angular component.
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
+ public email = '';
+ @ViewChild('emailInput', { static: true }) emailInput: IonInput;
}
First, bind the element value to an email property. Because the element is named #emailInput, use ViewChild to reference it through an emailInput property. Next, watch the element's change event.
+ async ngOnInit() {
+ const nativeEmailInput = await this.emailInput.getInputElement();
+ nativeEmailInput.addEventListener('change', (ev: Event) => {
+ requestAnimationFrame(() => {
+ this.email = (ev.target as HTMLInputElement).value;
+ });
+ });
+ }
ion-input wraps an input element that you can get with getInputElement. When the ngOnInit lifecycle hook runs, call this.emailInput.getInputElement() to get that input. Then use addEventListener to watch change and copy the detected value into the email property.
The catch with this approach is that change keeps firing even when the user types normally, so the value keeps updating. That is why I use requestAnimationFrame so the value from change is applied after normal binding. It is not very elegant. If you are willing to exclude the case where the user starts typing and then switches to autocomplete, you could do something like this instead:
async ngOnInit() {
const nativeEmailInput = await this.emailInput.getInputElement();
nativeEmailInput.addEventListener('change', (ev: Event) => {
if (this.email.length === 0) {
this.email = (ev.target as HTMLInputElement).value;
};
});
}
That way the value is applied only when email is empty. If you only need the first change event, you can remove the listener immediately after it fires.
Related issue: https://github.com/ionic-team/ionic-framework/issues/23335
Browser bug workarounds are never pretty, but I hope this helps.
See you next time.