Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

IoS Autofill data in login forms is empty in cordova application (using angular)

Cordova 8 / IoS 12 / Angular 6

I have a cordova application with a login form. Everything is working well apart from this.

On ios, the user is prompted by apple to enter a saved password when he focuses in the form. When the user uses this ios autofill feature, the form doest not detect the new values and the data stays empty. (but the user can see the credentials appearing on the screen)

Here is my login form :

 <form (ngSubmit)="login()" [formGroup]="loginForm">
        <input type="email" formControlName="username" name="username"/>
        <input type="password" formControlName="password" name="password"/>
        <button class="transparent-button primary">Login</button>
    </form>

And in my component :

 constructor(
    /* ... */
 ) {
  this.loginForm = formBuilder.group({
    username: ["", Validators.required],
    password: ["", Validators.required]
  });

};

login(){
    //this.loginForm.value.username and 
    this.loginForm.value.password stay empty when user 
    autofill
}

I also tried with template driven forms : same problem. Apple is now blocking the publishing of my app because of this. Is this a known problem of ios/cordova ?

Thanks

like image 519
Linwe Avatar asked Nov 30 '18 09:11

Linwe


3 Answers

For anyone that came across this in Ionic 5, this fix did the trick. I've tested this out on regular inputs too (instead of ion-input).

Apparently after the autofill is performed, the Angular (change) event is also triggered on the input field without focus, and this can be used to set the value of that form field. (as shown below):

<input ... (change)="form.controls[fieldName].setValue($event.target.value)">

As stated in the comment, even though the fix is mentioned in Ionic 3 repo, the user with the solution (as well as myself) tested it out in Ionic 5.

like image 110
JacobF7 Avatar answered Oct 02 '22 23:10

JacobF7


FWIW, I was having this same issue, see my workaround below.

I'm using reactive forms, and was experiencing the issue on a login form where I have just a username and password input. I implemented a workaround where I subscribe to changes on the form and then detect if the native password value is equal the password form field at the time of the change (technically 500ms after the change to wait for the autofill to input the password value). If the two are different I manually override the form value with the native value which triggers validation of the form.

Hope this helps someone!

// login-form.component.ts

import { Component, ViewChild, ElementRef } from '@angular/core';
import { FormGroup, FormBuilder, Validators } from '@angular/forms';

@Component({
  selector: 'app-login-form',
  template: require('./login-form.component.pug')(),
  styleUrls: ['./login-form.component.scss'],
})
export class LoginFormComponent {

  protected loginForm: FormGroup;

  @ViewChild('password') public passwordRef: ElementRef;

  constructor(private _formBuilder: FormBuilder) {
    this.loginForm = this.getForm();

    // NOTE: this hack triggers form validation on iOS autofill
    this.loginForm.valueChanges
      // wait for 500ms to be sure the autofill is finished with the password field
      .debounceTime(500)
      .subscribe((changes) => {
        // manually fetch the value from nativeElement
        let passVal = this.passwordRef.nativeElement.value; //(<HTMLInputElement>document.querySelector('[name="password"]')).value;
        // if the value saved in the form is different from the input, manually update it
        if (passVal !== changes.password) {
          this.loginForm.get('password').setValue(passVal);
        }
      })
    ;
    // NOTE: this hack triggers form validation on iOS autofill
  }

  protected getForm(): FormGroup {
    return this._formBuilder.group({
      username: ['', [
        Validators.required,
        Validators.email,
      ]],
      password: ['', [
        Validators.required,
      ]],
    });
  }

  public onSubmit(login: FormGroup) {
    // ...
  }
}
// login-form.component.pug
// NOTE: pug + bootstrap 4

h1 Login
form([formGroup]="loginForm", (ngSubmit)="onSubmit(loginForm)")
  .form-group
    input.form-control(
      formControlName="username",
      name="username",
      type="email",
      placeholder="Username",
      autocomplete="on",
      autocorrect="off",
      autocapitalize="off",
      spellcheck="false",
    )

  .form-group
    input.form-control(
      #password,
      formControlName="password",
      name="password",
      type="password",
      placeholder="Password",
      autocomplete="on",
      autocorrect="off",
      autocapitalize="off",
      spellcheck="false",
    )

  input.mb-3.btn.btn-lg(
    type="submit",
    value="Login",
    [class.btn-outline-primary]="loginForm.valid",
    [class.btn-outline-secondary]="!loginForm.valid",
    [disabled]="!loginForm.valid",
  )

like image 32
jspizziri Avatar answered Oct 03 '22 00:10

jspizziri


I can confirm. I'm having the same issue with Ionic using ngModel, but it also occurs using your code with formGroup.

<ion-item>
    <ion-label stacked>Benutzername</ion-label>
    <ion-input [(ngModel)]="username" id="un" type="text" autocomplete="on" autocorrect="on" clearInput="true" clearOnEdit="false"></ion-input>
</ion-item>
<ion-item>
    <ion-label stacked>Passwort</ion-label>
    <ion-input [(ngModel)]="password" id="pw" type="password" autocomplete="on" autocorrect="on" clearInput="true" clearOnEdit="false"></ion-input>
</ion-item>

The attributes autocomplete and autocorrect (Ionic Input Attributes) do not affect the iOS-Autofill feature.

Example App: I have created an example app using the Ionic Getting Started Guide to demonstrate this issue:

Example Login App

When typing in the credentials by hand, they are being stored in the variables (password and username) as you can see in the following image: Image 1

After setting the AutoFill-credentials in iOS's settings and restarting the simulator, i just clicked into the Username field and clicked on "Passwords" in the keyboard's top bar. Then i just selected the user to fill in. Everything looks allright and filled in correctly as you can see in Image 2

Then i clicked the Login-button and received the output of the username and password variables as shown in Image 3

As you can see, the username-field into which i tapped and used the AutoFill-feature has synced its value to its variable. But the password field (into which i never tapped becaus of the AutoFill-feature) does not sync its data to its variable.

When i tap into the password-field by hand and use the AutoFill-feature again, the data is synced with its variable correctly: Image 4

The same behavior goes the other way around, just tapping into the password's field using the AutoFill-feature. Then the password-field syncs its value to its variable, but the username-field does not.

like image 42
Jonathan W Avatar answered Oct 03 '22 00:10

Jonathan W