Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bug: form status classes (ion-invalid etc.) not applied correctly with Angular option eventCoalescing: true #30232

Open
3 tasks done
ReneZeidler opened this issue Mar 6, 2025 · 0 comments
Labels

Comments

@ReneZeidler
Copy link

Prerequisites

Ionic Framework Version

v8.x

Current Behavior

With the Angular option eventCoalescing: true, form validation styling behaves weirdly:

bug-ion-classes.mp4

Expected Behavior

In reference to the video above:

  • After typing "1", the "valid" styling should be visible. Instead, it is only visible after typing "2"
  • After clearing the input and moving focus out of it, it should be styled as "invalid", because it is touched and invalid. Instead, the styling only becomes "invalid" after triggering another blur event by clicking into and out of the form field.
  • After typing "3", the input should be styled as "valid". Instead, it is still styled as "invalid", and only gets the "valid" styles after typing "4"
  • After clearing the input field again, with focus still on the input, it should be styled as "invalid" because it is touched and invalid. Instead, the "invalid" styles only get applied after focus moves out of the input.

Steps to Reproduce

  1. Clone and run the reproduction repo below. The only special configuration in that repo is the following line in app.config.ts:
provideZoneChangeDetection({ eventCoalescing: true })
  1. Click in and out of he input field to mark it as "touched". It will display as invalid because the field is marked as required.
  2. Type a single character into the input field. It will still be visually shows as invalid, even though the FormControl state is valid.
  3. Remove the character again. It will be shown as valid, even though the FormControl state is invalid.

Code Reproduction URL

https://github.com/ReneZeidler/ionic-form-classes-bug

Ionic Info

Ionic:

Ionic CLI : 7.2.0 (/home/r718037/.nvm/versions/node/v20.18.1/lib/node_modules/@ionic/cli)
Ionic Framework : @ionic/angular 8.4.3
@angular-devkit/build-angular : 19.2.1
@angular-devkit/schematics : 19.2.1
@angular/cli : 19.2.1
@ionic/angular-toolkit : 12.1.1

Utility:

cordova-res : not installed globally
native-run : not installed globally

System:

NodeJS : v20.18.1 (/home/r718037/.nvm/versions/node/v20.18.1/bin/node)
npm : 11.0.0
OS : Linux 5.15

Additional Information

eventCoalescing is an Angular option to avoid running change detection multiple times for a single event. (The option runCoalescing coalesces change detection runs in even more cases, and implies the eventCoalescing option.)

What this means in practice is that change detection no longer gets run synchronously but asynchronously with requestAnimationFrame or setTimeout, whichever is faster. See the relevant code here:
https://github.com/angular/angular/blob/cae1fe519b4fc093ca99d0183a2c4da86a96bde1/packages/core/src/zone/ng_zone.ts#L381-L418
https://github.com/angular/angular/blob/cae1fe519b4fc093ca99d0183a2c4da86a96bde1/packages/core/src/util/callback_scheduler.ts#L11-L66
(The Angular documentation mentions this for runCoalescing, but not for eventCoalescing, even though it applies in both cases.)


The change detection running asynchronously seems to not play nicely with the logic that sets the Ionic form status classes (ion-invalid, ion-touched, etc.).

The method setIonicClasses gets called synchronously whenever the classes could change, e.g. in ionInput event handlers or by hooking into Angular's FormControl's markAs* methods. The method then delays the actual updating of the classes with requestAnimationFrame before looking at the corresponding ng-classes to mirror. This usually gives change detection time to run, in which the ng-classes are simply set via property binding.

However, with the eventCoalescing option enabled, the change detection now also gets delayed by requestAnimationFrame. Because setIonicClasses called raf first, it also gets executed first, and at that point the ng-classes haven't been updated yet.
(Technically, because change detection delays itself by a race between raf and setTimeout, it sometimes still wins. On my system this is rare, but that causes this bug to be slightly inconsistent. How often setTimeout wins depends on the overall system power and screen refresh rate.)

setIonicClasses needs to be guranteed to run after a full change detection cycle for the logic to be correct.

@ionitron-bot ionitron-bot bot added the triage label Mar 6, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant