Closed florian72810 closed 1 year ago
Thanks for the issue. I took a closer look at your GitHub repo and this appears to be a bug in WKWebView, which is the WebKit-based webview on iOS that Capacitor and Cordova applications use.
<ion-input>
relies on the input
event to be fired from the inner <input>
element in order for the value
property to be changed correctly since the autofill functionality sets the value on the inner <input>
, not the <ion-input>
Web Component. When autofilling on the password text field in WKWebView, this input
event is not fired for the email text field, even though its value changes. When running your app in Safari, the input
event is fired as expected.
I have reported this issue to the WebKit team for them to fix, and I have also noted that this is impacting your app's ability to get onto the iOS App Store: https://bugs.webkit.org/show_bug.cgi?id=226023.
I have put together this workaround you can use that should resolve the issue for now. Can you try it and let me know how it works in your application? I tested in your demo repo and it was working fine for me.
home.page.html
Email:
<ion-input #emailInput [(ngModel)]="email" type="email" name="email"></ion-input>
Password:
<ion-input #passwordInput [(ngModel)]="password" type="password" name="password"></ion-input>
home.page.ts
import { Component, ViewChild } from '@angular/core';
import { IonInput } from '@ionic/angular';
@Component({
selector: 'app-home',
templateUrl: 'home.page.html',
styleUrls: ['home.page.scss'],
})
export class HomePage {
@ViewChild('emailInput', { static: true }) emailInput: IonInput;
@ViewChild('passwordInput', { static: true }) passwordInput: IonInput;
public email = '';
public password = '';
constructor() {}
async ngOnInit() {
const nativeEmailInput = await this.emailInput.getInputElement();
const nativePasswordInput = await this.passwordInput.getInputElement();
nativeEmailInput.addEventListener('change', (ev: Event) => {
requestAnimationFrame(() => {
this.email = (ev.target as HTMLInputElement).value;
});
});
nativePasswordInput.addEventListener('change', (ev: Event) => {
requestAnimationFrame(() => {
this.password = (ev.target as HTMLInputElement).value;
});
});
}
}
The workaround works 👍
Any news on this ?
We are waiting for Apple to implement a fix in iOS. I will update this thread when I have more to share.
Any update?
As I said in my last comment, we are waiting for Apple to implement a fix in iOS.
Locking this thread for now since we have a good understanding of the issue. I will update this thread when I have more to share.
I've been struggling to make the workaround work for Ionic React. This is what I have so far but it still isn't right. When clicking the Log In
button it prints stale values. Clicking it again gets the latest values. Any help would be greatly appreciated.
UPDATE: See next comment for solution. I'm leaving this here as I'm still curious how something like this should work.
import React, {useCallback, useEffect, useRef, useState} from "react";
import {IonButton, IonCard, IonInput, IonItem} from "@ionic/react";
const LogInForm: React.FC = () => {
const emailRef = useRef<HTMLIonInputElement>(null);
const passwordRef = useRef<HTMLIonInputElement>(null);
const [email, setEmail] = useState<string>("");
const [password, setPassword] = useState<string>("");
// Workaround for https://github.com/ionic-team/ionic-framework/issues/23335
// where filling in multiple inputs from a password manager only updates the input with focus.
const onClickLogin = () => {
console.log("login:", email, password)
// logIn(email, password);
}
const emailChangeListener = useCallback(({target}) => {
requestAnimationFrame(() => {
setEmail((target as HTMLInputElement).value);
});
}, []);
const passwordChangeListener = useCallback(({target}) => {
requestAnimationFrame(() => {
setPassword((target as HTMLInputElement).value);
});
}, []);
useEffect( () => {
let emailInput: HTMLInputElement;
let passwordInput: HTMLInputElement;
emailRef.current?.getInputElement().then(input => {
emailInput = input;
emailInput?.addEventListener("change", emailChangeListener);
});
passwordRef.current?.getInputElement().then(input => {
passwordInput = input;
passwordInput?.addEventListener("change", passwordChangeListener);
});
return () => {
emailInput?.removeEventListener("change", emailChangeListener);
passwordInput?.removeEventListener("change", passwordChangeListener);
}
}, [emailChangeListener, passwordChangeListener]);
return (
<IonCard>
<IonItem>{email} / {password}</IonItem>
<IonItem><IonInput type="email" placeholder="email" ref={emailRef} /></IonItem>
<IonItem><IonInput type="password" placeholder="password" ref={passwordRef} /></IonItem>
<IonButton onClick={onClickLogin}>Log In</IonButton>
</IonCard>
);
}
export default LogInForm;
I think I have a much (much!) simpler solution:
import React, {useRef} from "react";
import {IonButton, IonCard, IonInput, IonItem} from "@ionic/react";
const LogInForm: React.FC = () => {
const emailRef = useRef<HTMLIonInputElement>(null);
const passwordRef = useRef<HTMLIonInputElement>(null);
// Workaround for https://github.com/ionic-team/ionic-framework/issues/23335
const onClickLogin = async () => {
const emailInput = await emailRef.current?.getInputElement()
const passwordInput = await passwordRef.current?.getInputElement()
console.log("login:", emailInput?.value, passwordInput?.value)
// logIn(emailInput?.value as string, passwordInput?.value as string);
}
return (
<IonCard>
<IonItem><IonInput type="email" placeholder="email" ref={emailRef} /></IonItem>
<IonItem><IonInput type="password" placeholder="password" ref={passwordRef} /></IonItem>
<IonButton onClick={onClickLogin}>Log In</IonButton>
</IonCard>
);
}
export default LogInForm;
Hi everyone,
I am posting here again as I am merging a related thread.
This thread is tracking a bug in WKWebView where the autofill feature in iOS is not updating the value
property in ion-input
. This bug impacts Cordova/Capacitor apps but does not impact apps running in mobile Safari.
I will post here when a fix has been shipped in iOS. In the meantime, if anyone has links to production apps that are impacted by this bug, please feel free to post them. This can sometimes help get WebKit bugs fixed faster.
It's worth noting too that this issue may be worked around with the changes we have proposed in https://github.com/ionic-team/ionic-framework/discussions/25532.
I'm having the same issues, but on Laravel with Livewire. Anyone that help with a javascript workaround?
@liamdebeasi can you explain how the changes proposed in #25532 allow for a workaround?
And until then, should we use the workaround described at https://forum.ionicframework.com/t/vuejs-password-autofill-value-empty/217195/3 ? (the solution doesn't work on my app for some reason, I still have the bug it seems the "change" events of the inputs are not triggered)
@liamdebeasi can you explain how the changes proposed in #25532 allow for a workaround?
And until then, should we use the workaround described at https://forum.ionicframework.com/t/vuejs-password-autofill-value-empty/217195/3 ? (the solution doesn't work on my app for some reason, I still have the bug it seems the "change" events of the inputs are not triggered)
In Ionic v6, the ionChange
event is emitted as a result of the value
property on the ion-input
component changing. This value
property is updated whenever the native input
event fires: https://github.com/ionic-team/ionic-framework/blob/f642c29f928803b3a103d43ecde495b890f43159/core/src/components/input/input.tsx#L358. Since the input
event does not fire in WKWebView when performing an autofill, the reported bug occurs.
In Ionic v7, we changed the ionChange
event to only emit when the native change
event fires on the <input>
element inside of ion-input
. The change
event fires as expected in WKWebView which means this issue is can be avoided.
Alright, I'm still using Ionic v6, that might be why I still have the bug, I did a workaround a bit similar to that linked in the forum above, by just reading the email and password values from the input fields using native API calls right when I needed them
is Ionic v7 ready for production?
Ionic v7 is still in development, but we plan on having a public beta in the future.
Hi everyone,
We recently merged our ion-input
revisions which will avoid this issue. Since the code to fix this issue has been merged, I am going to close this. This fix will be available in Ionic 7 as it requires breaking changes to how we emit the ionChange
event. As I mentioned in https://github.com/ionic-team/ionic-framework/issues/23335#issuecomment-1318729541, we will have a public beta of Ionic 7 so developers can test these changes and provide feedback. Please let me know if there are any questions. Thanks!
Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Ionic, please create a new issue and ensure the template is fully filled out.
Bug Report
I believe it is the same issue as #22682 and #22757, with reproduction instruction.
Ionic version:
[ ] 4.x [x] 5.x
Current behavior: On a login form using ion-input, the iOS Keychain does fill username and password. But the secondary ion-input item does not see changes. By "secondary" I mean the one that was not touched.
For example:
Or:
Expected behavior: Ion-Input should see the change of the underlying input item.
Steps to reproduce:
Sample project based on ionic starter blank: https://github.com/florian72810/ion-input-password-ios-keychain
The issue happens on real device or simulator, I checked on "Simulator iPod touch 7th Generation - iOS 14.5", "Simulator iPod touch 7th Generation - iOS 13.0", and also on real device "iPhone XS Max - iOS 14.5".
The iOS Keychain need to have some content. You have to enable it first and put some data. (see screenshot at bottom)
If you are using a simulator, you have to disconnect the hardware keyboard in order to see the visual keyboard: I/O > Keyboard > Connect Hardware Keyboard (unchecked).
On the following video, you can see the bug.
https://user-images.githubusercontent.com/20518933/118987623-1e016c80-b989-11eb-890e-7611df8c0882.mp4
Other information:
The AppStore validation team seem to be using the keychain to test app because they refused my app yesterday due to this bug.
It is still possible to access the native input field to bypass this bug.
Ionic info: