cordova-plugin-ionic-webview
cordova-plugin-ionic-webview copied to clipboard
Login form validation issues with auto-fill from password manager
firstly, two important notes here:
- I do not have the issue described in #636. I use Bitwarden password manager, and I get the "Passwords" input auto-fill option exactly as expected every time.
- I do not have access to a Mac for debugging this issue.. I've requested one from my boss numerous times, but nothing has happened with that process as yet. the only device I currently have for testing is a 6th gen iPad running
15.3.1 (19D52)
.
when running the app on iOS, selecting either the "email" or "password" and filling in details with a password manager does not mark the other field as "filled in", resulting in the "Login" button remaining disabled with no further feedback.
because the "Passwords" auto-fill prompt only appears when a login form is given focus, the observed behaviour changes depending on which field was focused to initiate this process. where the problem described here will then affect the other input field.
furthermore, the form field validation messages only show for an input field after that field has received and lost focus. I would assume in order to validate the user's input after something is entered.
see the following screenshots for clarification (app logo and email address obscured for privacy reasons, this is an un-announced application for my current employer):
auto-fill with "email" field focussed | auto-fill with "password" field focussed |
---|---|
![]() |
![]() |
incorrect error shows up after focussing and leaving the "password" input field. | incorrect error shows up after focussing and leaving the "email" input field. |
please note: this problem does not happen on Android, both login form fields refresh correctly and the "Login" button is enabled as expected.
my ionic info
output is as follows:
Ionic:
Ionic CLI : 6.19.0 (C:\Users\agreeff\AppData\Local\Volta\tools\image\packages\@ionic\cli\node_modules\@ionic\cli)
Ionic Framework : @ionic/angular 6.0.12
@angular-devkit/build-angular : 12.2.16
@angular-devkit/schematics : 12.2.16
@angular/cli : 12.2.16
@ionic/angular-toolkit : 5.0.3
Cordova:
Cordova CLI : 11.0.0
Cordova Platforms : android 10.1.1
Cordova Plugins : cordova-plugin-ionic-keyboard 2.2.0, cordova-plugin-ionic-webview 5.0.0, cordova-plugin-ionic 5.5.1, (and 4 other plugins)
Utility:
cordova-res : 0.15.4
native-run : 1.5.0
System:
Android SDK Tools : 26.1.1 (C:\android-sdk)
NodeJS : v14.19.0 (C:\Users\agreeff\AppData\Local\Volta\tools\image\node\14.19.0\node.exe)
npm : 6.14.16
OS : Windows 10
and my package.json
file lists the following dependencies:
{
"dependencies": {
"@angular/common": "12.2.16",
"@angular/core": "12.2.16",
"@angular/forms": "12.2.16",
"@angular/platform-browser": "12.2.16",
"@angular/platform-browser-dynamic": "12.2.16",
"@angular/router": "12.2.16",
"@awesome-cordova-plugins/app-version": "5.40.0",
"@awesome-cordova-plugins/core": "5.40.0",
"@awesome-cordova-plugins/firebase-x": "5.40.0",
"@awesome-cordova-plugins/splash-screen": "5.40.0",
"@awesome-cordova-plugins/status-bar": "5.40.0",
"@ionic/angular": "6.0.12",
"@ionic/storage": "3.0.6",
"@ionic/storage-angular": "3.0.6",
"cordova-android": "10.1.1",
"cordova-ios": "6.2.0",
"rxjs": "6.6.7",
"tslib": "2.3.1",
"zone.js": "0.11.5"
},
"devDependencies": {
"@angular-devkit/build-angular": "12.2.16",
"@angular-eslint/builder": "12.7.0",
"@angular-eslint/eslint-plugin": "12.7.0",
"@angular-eslint/eslint-plugin-template": "12.7.0",
"@angular-eslint/template-parser": "12.7.0",
"@angular/cli": "12.2.16",
"@angular/compiler": "12.2.16",
"@angular/compiler-cli": "12.2.16",
"@angular/language-service": "12.2.16",
"@ionic/angular-toolkit": "5.0.3",
"@types/jasmine": "3.10.4",
"@types/jasminewd2": "2.0.10",
"@types/node": "14.18.12",
"@typescript-eslint/eslint-plugin": "5.16.0",
"@typescript-eslint/parser": "5.16.0",
"cordova-plugin-app-version": "0.1.13",
"cordova-plugin-device": "2.0.3",
"cordova-plugin-firebasex": "git+https://github.com/dpa99c/cordova-plugin-firebasex.git#751ba5a35fe7461731cde6a1ea5fd1b973941572",
"cordova-plugin-ionic": "5.5.1",
"cordova-plugin-ionic-keyboard": "2.2.0",
"cordova-plugin-ionic-webview": "5.0.0",
"cordova-plugin-splashscreen": "6.0.0",
"cordova-plugin-statusbar": "3.0.0",
"eslint": "7.32.0",
"eslint-plugin-import": "2.25.4",
"eslint-plugin-jsdoc": "30.7.13",
"eslint-plugin-prefer-arrow": "1.2.3",
"jasmine-core": "3.99.1",
"jasmine-spec-reporter": "5.0.2",
"karma": "6.3.17",
"karma-chrome-launcher": "3.1.1",
"karma-coverage": "2.2.0",
"karma-coverage-istanbul-reporter": "3.0.3",
"karma-jasmine": "4.0.1",
"karma-jasmine-html-reporter": "1.7.0",
"prettier": "2.6.0",
"protractor": "7.0.0",
"ts-node": "8.10.2",
"typescript": "4.4.4"
}
}
my login.page.html
file contains the following:
<ion-content>
<form (ngSubmit)="login()" [formGroup]="credentials" class="login-form">
<div class="login-logo-wrapper">
<img src="/assets/app-logo.png" alt="Application Logo" class="login-logo" />
</div>
<div class="input-group">
<ion-item>
<ion-input type="email" placeholder="Email" formControlName="email"></ion-input>
</ion-item>
<div *ngIf="(email.dirty || email.touched) && email.errors" class="errors">
<span *ngIf="email.errors?.required">Email is required</span>
<span *ngIf="email.errors?.pattern">Email is invalid</span>
</div>
<ion-item>
<ion-input type="password" placeholder="Password" formControlName="password"></ion-input>
</ion-item>
<div *ngIf="(password.dirty || password.touched) && password.errors" class="errors">
<span *ngIf="password.errors?.required">Password is required</span>
</div>
</div>
<ion-button type="submit" expand="block" [disabled]="!credentials.valid">Log in</ion-button>
</form>
</ion-content>
while my login.page.ts
component file contains the following (with unrelated code blocks removed):
@Component({
selector: "app-login",
templateUrl: "./login.page.html",
styleUrls: ["./login.page.scss"],
})
export class LoginPage implements OnInit {
credentials: FormGroup;
private loginLoader: HTMLIonLoadingElement;
constructor(
private formBuilder: FormBuilder,
private authService: AuthenticationService,
private loadingController: LoadingController,
) {}
get email() {
return this.credentials.get("email");
}
get password() {
return this.credentials.get("password");
}
async ngOnInit() {
const emailValidationPattern = /^[a-zA-Z0-9_!#$%&'*+/=?`{|}~^-]+(?:\\.[a-zA-Z0-9_!#$%&'*+/=?`{|}~^-]+)*@[a-zA-Z0-9-]+(?:\\.[a-zA-Z0-9-]+)*$/;
this.credentials = this.formBuilder.group({
email: ["", [Validators.required, Validators.pattern(emailValidationPattern)]],
password: ["", [Validators.required]],
});
this.loginLoader = await this.loadingController.create();
this.loginLoader.message = "Initialising...";
this.loginLoader.present();
// attempt to auto-login using a "refresh token"
await this.authService.refreshAuthToken();
this.loginLoader.dismiss();
}
}
old webkit bug whereas autofill does not emit an input event
Workaround is to register a change event handler as in https://gist.github.com/dtarnawsky/fc92869c1c67b9c74c66de8af3e081b2
See also https://capacitorjs.com/docs/guides/autofill-credentials