Ionic-framework: [Ionic 4.0.1 iOS pwa] Keyboard blocks input field

Created on 7 Feb 2019  路  5Comments  路  Source: ionic-team/ionic-framework

Bug Report

Ionic 4.0.1

Current behavior:
Keyboard blocks input on iOS when using Safari or Chrome and as saved to start (pwa).
This behaviour does not happen when using Chrome on Android

In the image the password input field that is being edited is not even seen.
When using Chrome you are not even able to scroll manually the input field up

img_0485

Expected behavior:
Input should be pushed above keyboard to be able to see what is being typed

Steps to reproduce:
Any form in which an input is below the area in which keyboard will be presented

Ionic:

   ionic (Ionic CLI)             : 4.10.2 (/Users/ale/.npm-global/lib/node_modules/ionic)
   Ionic Framework               : @ionic/angular 4.0.1
   @angular-devkit/build-angular : 0.12.4
   @angular-devkit/schematics    : 7.2.4
   @angular/cli                  : 7.2.4
   @ionic/angular-toolkit        : 1.3.0

Cordova:

   cordova (Cordova CLI) : 8.1.2 ([email protected])
   Cordova Platforms     : none
   Cordova Plugins       : cordova-plugin-ionic-keyboard 2.1.3, cordova-plugin-ionic-webview 2.3.2, (and 4 other plugins)

System:

   NodeJS : v10.14.2 (/usr/local/bin/node)
   npm    : 6.6.0
   OS     : macOS Mojave
stale issue investigation angular core

All 5 comments

Didd you use a ion-content and an ion-input? Because if you use custom elements it will not work (at least in ionic 3)
How is your code setup?

I'm also running into this on Android (on iOS there's no problem).

Steps to reproduce:

  1. ionic start (create blank Ionic 4 app)
  2. edit home.page.html to contain the following:
<ion-header>
    <ion-toolbar>
        <ion-title>
            Ionic Blank
        </ion-title>
    </ion-toolbar>
</ion-header>

<ion-content padding>
    The world is your oyster.
    <p>If you get lost, the <a target="_blank" rel="noopener" href="https://ionicframework.com/docs/">docs</a> will be
        your guide.</p>
    <div style="height:1000px; background-color: grey">&nbsp;</div>
    a <ion-input type="text"></ion-input><br/>
    b <ion-input type="text"></ion-input><br/>
    c <ion-input type="text"></ion-input><br/>
</ion-content>
  1. ionic cordova run android
  2. scroll down
  3. focus an input
  4. result:
    screenshot_20190213-155228_myapp

Expected:
screenshot_20190213-155232_myapp

$ ionic info

Ionic:

   ionic (Ionic CLI)             : 4.10.2 (~/.nvm/versions/node/v8.15.0/lib/node_modules/ionic)
   Ionic Framework               : @ionic/angular 4.0.1
   @angular-devkit/build-angular : 0.12.4
   @angular-devkit/schematics    : 7.2.4
   @angular/cli                  : 7.2.4
   @ionic/angular-toolkit        : 1.3.0

Cordova:

   cordova (Cordova CLI) : 8.1.2 ([email protected])
   Cordova Platforms     : android 7.1.4, browser 5.0.4, ios 4.5.5
   Cordova Plugins       : cordova-plugin-ionic-keyboard 2.1.3, cordova-plugin-ionic-webview 3.1.2, (and 4 other plugins)

System:

   Android SDK Tools : 26.1.1 (~/Library/Android/sdk)
   ios-deploy        : 1.9.2
   ios-sim           : 6.1.2
   NodeJS            : v8.15.0 (~/.nvm/versions/node/v8.15.0/bin/node)
   npm               : 6.4.1
   OS                : macOS Mojave
   Xcode             : Xcode 10.1 Build version 10B61

@StefanRein I am using ion-content and an ion-input

Also ion-list with ion-items, a form, ion-grid with ion-row and ion-col too.
Might that have anything to do?

<ion-header>
  <ion-toolbar>
      <ion-title>
          Login
      </ion-title>
  </ion-toolbar>
</ion-header>

<ion-content padding>

    <ion-grid>

      <ion-row justify-content-center>
        <ion-col size-md="6">

          <form [formGroup]="loginForm" (ngSubmit)="loginUser()" novalidate>

          <ion-list>

            <ion-item>

              <img  class="logo" [src]="quadriImg">
            </ion-item>

            <ion-item>
              <ion-label position="fixed">Email</ion-label>
              <ion-input formControlName="email" type="email" [class.invalid]="!loginForm.controls.email.valid && loginForm.controls.email.touched">
              </ion-input>
            </ion-item>

            <ion-item>
              <ion-label position="fixed">Constrase帽a</ion-label>
              <ion-input formControlName="password" type="password" [class.invalid]="!loginForm.controls.password.valid && loginForm.controls.password.touched">
              </ion-input>
            </ion-item>

            <ion-button margin-top fill="outline" expand="block" type="button" [disabled]="!loginForm.valid" (click)="loginUser()" >
              Iniciar sesion
            </ion-button>
          </ion-list>

          </form>

        </ion-col>


      </ion-row>

    </ion-grid>

  </ion-content>

Hey guys,

@alejandroquadri @jaco-terbraak

right now I can only speak for Ionic 3 and maybe some team member could explain what's happening and where in Ionic 4.

Let's start with HTML5 first (because our team started everything just without the Ionic Input fields and run into some weird problems):

HTML5

Because of the nested structure of position: absolute elements, on iOS the native scrolling behavior is really bad / laggy. Therefore are some CSS properties like -webkit-overflow: touch. And some other scroll optimizing CSS.

-webkit-overflow-scrolling: touch;
will-change: scroll-position;
contain: size style layout;

But if you would normally scroll and have an HTML field, the caret in the focused input field would not update his position while scrolling.
That is is a well known bug since October 2014: https://bugs.webkit.org/show_bug.cgi?id=138201

Also if you would focus an input field, when the keyboard would show up, the input field would just stay where it is and the keyboard would overlap.

If you would enable the keyboard accessory bar and then would press up or down, the input field would scroll into the view.

Then you would also need to calculate on input focus, if it is in the view or not and call scrollIntoView (https://developer.mozilla.org/de/docs/Web/API/Element/scrollIntoView)

The height was not calculated correctly somehow in the WkWebview, with:

<preference name="KeyboardResizeMode" value="ionic" />

but with

<preference name="KeyboardResizeMode" value="native" /> it was fine.

Here is the Objective C code for the plugin:

https://github.com/ionic-team/cordova-plugin-ionic-keyboard/blob/master/src/ios/CDVIonicKeyboard.m#L297

Then the keyboard behavior on some android was messed up.

Ionic 3

The above mentioned optimizations are seen in following element:
.scroll-content, who is a child element of ion-content

So our scrolling element is ion-content. And the elements we want to scroll is our ion-input.
Let's see into the input.ts:

https://github.com/ionic-team/ionic-v3/blob/master/src/components/input/input.ts#L283

So one problem occurred on our side: The ion-content was not injected by dependency injection, because of content projection of custom components, which did have the ion-inputs as parent.
Right now there is no other way (as far as I see) as to get these references and register and call everything again yourself.

my-modal.component.ts
Parent component, get reference to the Content.

@ViewChild('ionContent', {read: Content})
public ionContent: Content;

Ion-Input component wrapper component, which gets the reference to the ion-content and has as parent the above component:

form-input-wrapper.component.ts

@ViewChild('inputElement', {read: TextInput})
public readonly inputElement: TextInput;

constructor(@Optional() private myModal: MyModalComponent) {
}

public ngAfterViewInit(): void {
    if (this.myModal) {
        this.myModal.updateIonInputScrollAssist(this.inputElement);
    }
}

updateIonInputScrollAsssist method (hacking private things is really bad!)

public updateIonInputScrollAssist(ionInput: TextInput) {
    (<any>ionInput)._content = this.ionContent;

    const hideCaretOnScroll = this.config.getBoolean('hideCaretOnScroll', false);

    if (hideCaretOnScroll) {
        ionInput._enableHideCaretOnScroll();
    }
    const win = this.platform.win() as any;
    const keyboardPlugin = win.Ionic && win.Ionic.keyboardPlugin;
    if (keyboardPlugin) {
        const keyboardResizes = this.config.getBoolean('keyboardResizes', false);
        if (keyboardResizes) {
            ionInput._keyboardHeight = this.config.getNumber('keyboardSafeArea', 60);
            ionInput._enableScrollMove();
        } else {
            ionInput._enableScrollPadding();
            ionInput._enableScrollMove();
        }

    } else {
        ionInput._useAssist = this.config.getBoolean('scrollAssist', false);
        const usePadding = this.config.getBoolean('scrollPadding', ionInput._useAssist);
        if (usePadding) {
            ionInput._enableScrollPadding();
        }
    }
}

After this we also encountered another problem, still it was not working with our setup. We used the grid and some other elements which had position: relative.

Two problems here:

getScrollData method (I think also problems with offsetTop, but not 100% sure yet)
https://github.com/ionic-team/ionic-v3/blob/master/src/components/input/input.ts#L494

and cloneInputComponent, hiding the caret while scrolling by copying the elements:
https://github.com/ionic-team/ionic-v3/blob/master/src/components/input/input.ts#L823

Because of position: relative the offsetTop property is wrong. You would need to calculate the offset of all parents.

Ionic 4

Where is the code, solving these issues? Was this solved another way? How was this solved?
There were no mentioning about this in ionic 3 or 4 (maybe I overlooked something, please provide me some link).

Content:
https://github.com/ionic-team/ionic/blob/master/core/src/components/content/content.tsx

Input:
https://github.com/ionic-team/ionic/blob/master/core/src/components/input/input.tsx

I don't see copying / cloning elements or something like that, as it was before.

@danbucholtz @brandyscarney
Our team encountered a lot of problems until we figured out what was happening, can someone please provide some insights? Or if there is a documentation, provide a link for that.
We really want to move forward to Ionic 4 in some months, but still there were some other issues. I think they will be also resolved soon. But please don't let us move to Ionic 4 and encounter again these problems.

I had not the time to set up a repository for Ionic 4 yet, which will verify this, because we want to launch in some month and will stick with Ionic 3 for now until release.

Thanks for the issue! This issue is being closed due to inactivity. 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.

Thank you for using Ionic!

Was this page helpful?
0 / 5 - 0 ratings

Related issues

brandyscarney picture brandyscarney  路  3Comments

fdnhkj picture fdnhkj  路  3Comments

alexbainbridge picture alexbainbridge  路  3Comments

alan-agius4 picture alan-agius4  路  3Comments

BilelKrichen picture BilelKrichen  路  3Comments