Ionic input losing focus and closing keyboard

Me and my friends are struggling to solve this problem. We’ve seen similar topics but we couldn’t solve them.

In some pages of our app, when clicking on some input, after a few seconds the focus is lost and the keyboard closes. This time varies, sometimes it loses right after clicking, sometimes it takes 30 seconds. This is impacting app usage.

On some pages this does not happen. I’ve already replicated the exact same code, in one the focus is lost, and in another, it’s not.

When the input is inside a component, the error also happens.

I tried many possible solutions that I found around, but without success.

Here is the package.json :

{
  "name": "xxxxxxx",
  "version": "7.3.0",
  "author": "Ionic Framework",
  "homepage": "https://ionicframework.com/",

  "scripts": {
    "ng": "ng",
    "start": "ng serve",
    "build": "ng build",
    "test": "ng test",
    "lint": "ng lint",
    "e2e": "ng e2e"
  },

  "private": true,

  "dependencies": {
    "@angular/common": "^10.2.0",
    "@angular/core": "^10.2.0",
    "@angular/forms": "^10.2.0",
    "@angular/http": "^7.2.16",
    "@angular/platform-browser": "^10.2.5",
    "@angular/platform-browser-dynamic": "^10.2.0",
    "@angular/router": "^10.2.0",
    "@ionic-native/barcode-scanner": "^5.30.0",
    "@ionic-native/core": "^5.29.0",
    "@ionic-native/fingerprint-aio": "^5.29.0",
    "@ionic-native/splash-screen": "^5.29.0",
    "@ionic-native/status-bar": "^5.29.0",
    "@ionic/angular": "^5.4.1",
    "br-mask": "0.0.10",
    "chart.js": "^2.9.3",
    "chartjs-plugin-labels": "^1.1.0",
    "cordova-android": "^9.1.0",
    "cordova-plugin-fingerprint-aio": "^4.0.1",
    "core-js": "^3.6.5",
    "ionic-angular": "^3.9.10",
    "ionic-mqtt": "github:emalherbi/ionic-mqtt",
    "ionic-selectable": "^4.9.0",
    "moment": "^2.29.1",
    "ng2-charts": "^2.3.0",
    "rxjs": "^6.6.3",
    "rxjs-compat": "^6.6.7",
    "tslib": "^2.0.3",
    "uuid": "^8.3.1",
    "zone.js": "^0.11.2"
  },

  "devDependencies": {
    "@angular-devkit/build-angular": "^0.1002.0",
    "@angular/cli": "^10.2.0",
    "@angular/compiler": "^10.2.0",
    "@angular/compiler-cli": "^10.2.0",
    "@angular/language-service": "^10.2.0",
    "@ionic/angular-toolkit": "^2.3.3",
    "@types/jasmine": "^3.6.0",
    "@types/jasminewd2": "~2.0.3",
    "@types/node": "^14.14.6",
    "@types/uuid": "^8.0.0",
    "codelyzer": "^6.0.1",
    "cordova-ios": "^6.1.1",
    "cordova-plugin-device": "^2.0.2",
    "cordova-plugin-ionic-keyboard": "^2.2.0",
    "cordova-plugin-ionic-webview": "^5.0.0",
    "cordova-plugin-splashscreen": "^6.0.0",
    "cordova-plugin-statusbar": "^2.4.2",
    "cordova-plugin-whitelist": "^1.3.3",
    "grunt": "^1.1.0",
    "grunt-config": "^1.0.0",
    "grunt-contrib-clean": "^2.0.0",
    "grunt-contrib-copy": "~1.0.0",
    "grunt-prompt": "^0.2.0",
    "grunt-replace": "^0.7.4",
    "grunt-shell": "^3.0.1",
    "jasmine-core": "^3.5.0",
    "jasmine-spec-reporter": "^6.0.0",
    "karma": "^5.2.3",
    "karma-chrome-launcher": "^3.1.0",
    "karma-coverage-istanbul-reporter": "^3.0.2",
    "karma-jasmine": "^4.0.1",
    "karma-jasmine-html-reporter": "^1.4.0",
    "phonegap-plugin-barcodescanner": "^8.1.0",
    "protractor": "^7.0.0",
    "ts-node": "^9.0.0",
    "tslint": "^6.1.2",
    "typescript": "^4.0.5"
  },

  "description": "An Ionic project",
  "cordova": {
    "plugins": {
      "cordova-plugin-whitelist": {},
      "cordova-plugin-statusbar": {},
      "cordova-plugin-device": {},
      "cordova-plugin-splashscreen": {},
      "cordova-plugin-ionic-webview": {
        "ANDROID_SUPPORT_ANNOTATIONS_VERSION": "27.+"
      },
      "cordova-plugin-ionic-keyboard": {},
      "cordova-plugin-fingerprint-aio": {
        "FACEID_USAGE_DESCRIPTION": "Login now...."
      },

      "phonegap-plugin-barcodescanner": {
        "ANDROID_SUPPORT_V4_VERSION": "27.+"
      }
    },
    "platforms": [
      "ios",
      "android"
    ]
  }
}

Here is an example of input that loses focus

<div class="ion-padding">
        <ion-item>
          <ion-label color="primary">Cliente</ion-label>
          <ion-input formControlName="NOMEENTIDADE" type="text" required></ion-input>
        </ion-item>
        <ion-item>
          <ion-label color="primary">Funcionário</ion-label>
          <ion-input formControlName="NOMEFUNCIONARIO" disable readonly="true" type="text" (click)="addFuncionario()"></ion-input>
        </ion-item>
        <ion-item>
          <ion-label color="primary">Endereço</ion-label>
          <ion-input formControlName="ENDERECO" type="text"></ion-input>
        </ion-item>
        <ion-item>
          <ion-label color="primary">Telefone</ion-label>
          <ion-input formControlName="FONE" type="number"></ion-input>
        </ion-item>
        <ion-item>
          <ion-label color="primary">Celular</ion-label>
          <ion-input formControlName="CELULAR" type="number"></ion-input>
        </ion-item>
        <ion-item>
          <ion-label color="primary">Obs</ion-label>
          <ion-input formControlName="OBS" type="text"></ion-input>
        </ion-item>
      </div>

Here is his directory. For example, an input in the html in “pag-comanda” in blue, does not lose focus. An input in the html of “pag-comanda-itens”, in green, loses focus.

Thank you! If you need more information, just ask.

3 Likes

I am having a similar issue with one of my apps.
For me, it is an ion-textarea that loses focus.
The weird thing is that it only happens if I click on another text area and click back.

@leomoreno8 - did you ever figure out what the culprit was?

I’ve been tracking this issue for a few days with no luck.
I have two IonTextAreas.

  • Area1 is read-only.
  • Area2 is not read-only.

If I quickly click from Area1 to Area2, Area2 gains focus for less than a second, then Area1 steals the focus back, closing the keyboard.

I added an ionBlur event handler to Area2 and log the following from the event:

  • event.detail.target - Confirms that Area2 is the component that lost the focus
  • event.detail.relatedTarget - Confirms that Area1 is stealing the focus from Area2
  • The stack trace.

Here is the stack trace:

 Trace
trace
onAreaTwoBlur(main.4481161f48426204591a.js:416575)
executeListenerWithErrorHandling 
(main.4481161f48426204591a.js:48420)
wrapListenerIn_markDirtyAndPreventDefault 
(main.4481161f48426204591a.js:48464)
(anonymous function) (main.4481161f48426204591a.js:101305)
onInvokeTask (main.4481161f48426204591a.js:64233)
(anonymous function) (polyfills.3b79c05df71f6f04dc25.js:264)
(anonymous function) (polyfills.3b79c05df71f6f04dc25.js:609)
invokeTask (polyfills.3b79c05df71f6f04dc25.js:2127)
globalCallback (polyfills.3b79c05df71f6f04dc25.js:2164)
dispatchEvent
emitEvent (main.4481161f48426204591a.js:165741)
(anonymous function) (4783.60a1463e7151c1f43ec1.js:118)
**focus**
(anonymous function) (3470.ccf95d3270dfd1ba5bf3.js:281)
generatorResume
asyncGeneratorStep (main.4481161f48426204591a.js:421991)
_next (main.4481161f48426204591a.js:422013)
(anonymous function) (polyfills.3b79c05df71f6f04dc25.js:207)
(anonymous function) (polyfills.3b79c05df71f6f04dc25.js:1627)
(anonymous function) (polyfills.3b79c05df71f6f04dc25.js:264)
drainMicroTaskQueue (polyfills.3b79c05df71f6f04dc25.js:734)
(anonymous function) (polyfills.3b79c05df71f6f04dc25.js:612)

I used Safari dev tools to click through to the anonymous function called directly before focus to look at the code to see where the focus method is being called on Area1. Here is the code that I found:

/**
 * Relocating/Focusing input causes the
 * click event to be cancelled, so
 * manually fire one here.
 */
raf(() => componentEl.click());
/* tslint:disable-next-line */
if (typeof window !== 'undefined') {
    let scrollContentTimeout;
    const scrollContent = async () => {
// clean up listeners and timeouts
        if (scrollContentTimeout !== undefined) {
            clearTimeout(scrollContentTimeout);
        }
        window.removeEventListener('ionKeyboardDidShow',
            doubleKeyboardEventListener);
        window.removeEventListener('ionKeyboardDidShow', scrollContent);
// scroll the input into place
        if (contentEl) {
            await contentEl.scrollByPoint(0, scrollData.scrollAmount,
                scrollData.scrollDuration);
        }
// the scroll view is in the correct position now
// give the native text input focus
        relocateInput(componentEl, inputEl, false, scrollData.inputSafeY);
// ensure this is the focused input
        inputEl.focus();  // XXXX <--- This is the call that is stealing the focus from Area2.
    };
   /***
    Code removed for brevity
   ***/
    scrollContent();
}
};

It seems that Ionic is attempting to scroll the input into view, but it is causing Area1 to get the focus instead of leaving it on Area2. However, both IonTextAreas are already in view so there is no need to scroll.

I also saw found this code when I clicked through to the method called directly after focus:

this.onFocus = (ev) => {
    this.hasFocus = true;
    this.focusChange();
    if (this.fireFocusEvents) {
        this.ionFocus.emit(ev);
    }
};

I was curious about the check on this.fireFocusEvents variable so I looked for it and found this code above:

/**
* This is required for a WebKit bug which requires us to
* blur and focus an input to properly focus the input in
* an item with delegatesFocus. It will no longer be needed
* with iOS 14.
*
* @internal
*/
this.fireFocusEvents = true;

I have iOS 16 on the device, so I tried to set this to false on both text areas, but it did nothing, which kind of makes sense because it happens after the problem.

I attempted to upgrade from Ionic 5.9.3 to the latest 6.3.4, and I still have the same issue.

Does anyone have ideas on how I can work around this?

After typing this, I found this post:

This code did the trick:

IonicModule.forRoot({ scrollAssist: false }),