ionic-team/ionic-framework

appAutoFocus causes modal to freeze on presentation

VincenzoManto opened this issue · 0 comments

Ionic version:
[x] 7.x
[ ] 6.x
[ ] 5.x
[ ] 4.x

on Angular


I'm submitting a ...
[x] bug report
[ ] feature request


Current behavior:
When using the appAutoFocus directive on an ion-input in the calling page (not the modal), presenting a modal using modalController.present() causes the app to freeze or become unresponsive. The issue appears to stem from the appAutoFocus directive repeatedly requesting focus for the ion-input in the calling page, leading to a conflict with the modal's lifecycle.


Expected behavior:
The modal should present smoothly without being affected by directives or inputs in the calling page. The appAutoFocus directive should not interfere with the modal's focus management.


Steps to reproduce:

  1. Create a page with an ion-input using the appAutoFocus directive.
  2. Add a button on the page to open a modal using modalController.
  3. Present the modal.
  4. Observe the app freezing or becoming unresponsive.

Related code:

Calling Page:

<ion-app>
  <ion-content>
    <ion-input appAutoFocus placeholder="Focus me"></ion-input>
    <ion-button expand="block" (click)="presentModal()">Open Modal</ion-button>
  </ion-content>
</ion-app>

Component Code:

import { Component } from '@angular/core';
import { ModalController } from '@ionic/angular';
import { SearchResultPage } from './search-result.page';

@Component({
  selector: 'app-root',
  templateUrl: 'app.component.html',
  styleUrls: ['app.component.scss'],
})
export class AppComponent {
  constructor(private modalController: ModalController) {}

  async presentModal() {
    const modal = await this.modalController.create({
      component: SearchResultPage, // the behaviour is indipendent from modal content
      backdropDismiss: false,
    });

    await modal.present();
  }
}
@Directive({
    selector: '[appAutofocus]',
})

/**
 * direttiva per impostare AutoFocus su campo di input
 */
export class AutofocusDirective implements AfterContentChecked {
    constructor(private element: IonInput) {
    }

    ngAfterContentChecked(): void {
        this.element.setFocus();
    }
}

Other information:
This issue can be temporarily avoided by disabling the appAutoFocus directive before presenting the modal and re-enabling it after the modal is dismissed, as shown below:

async presentModal() {
  const input = document.querySelector('ion-input[appAutoFocus]');
  if (input) {
    input.removeAttribute('appAutoFocus');
  }

  const modal = await this.modalController.create({
    component: SearchResultPage,
    backdropDismiss: false,
  });

  await modal.present();

  await modal.onDidDismiss();
  if (input) {
    input.setAttribute('appAutoFocus', '');
  }
}

It seems that the appAutoFocus directive is not paused or detached from the calling page when the modal takes focus. This leads to a conflict where both the modal and the calling page attempt to manage focus.

The appAutoFocus directive should detect when its parent component loses focus (e.g., when a modal is presented) and temporarily stop requesting focus until the parent regains visibility.