ionic-framework: bug: changing value of component in ionChange results in an infinite loop

Bug Report

Ionic version: [x] 4.7.11

Current behavior: When the value of an Ionic input element is changed from OUTSIDE of the element, the element’s onIonChange is triggered, thereby duplicating the change event.

Expected behavior: As with every other React input, the onIonChange should only be triggered when the value was change from the element itself.

Steps to reproduce: See console in included stackblitz.

  1. Both the IonInput and regular input are controlled via the same value.
  2. When changing it from the IonInput, only the onIonChange is triggered.
  3. When changing it from the regular input, the input’s onChange is called AS WELL AS the onIonChange from the IonInput.

Related code: https://stackblitz.com/edit/ionic-v4-11-7-controlled-inputs

Other information: This same bug is happening with other Ionic inputs as well. I haven’t tested all of them, but it is happening with at least IonToggle and IonDateTime.

This is bad because unless each input has its own separate controlled state, doing something like clearing a state object could trigger 10+ onIonChange events, leading to race conditions and other annoyances.

Ionic info:

Ionic:

   Ionic CLI       : 5.4.13 (/Users/evan/.config/yarn/global/node_modules/ionic)
   Ionic Framework : @ionic/react 4.11.7

Capacitor:

   Capacitor CLI   : 1.4.0
   @capacitor/core : 1.4.0

Utility:

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

System:

   NodeJS : v13.1.0 (/usr/local/Cellar/node/13.1.0/bin/node)
   npm    : 6.12.1
   OS     : macOS Catalina

About this issue

  • Original URL
  • State: closed
  • Created 5 years ago
  • Reactions: 22
  • Comments: 28 (6 by maintainers)

Commits related to this issue

Most upvoted comments

And as a followup, it seems that other inputs don’t have onIonInput or anything like it that only triggers for inputs via that element. For example, IonDateTime and IonToggle only have onIonChange. What are we supposed to do in those cases?

ionChange is triggered with every change of the input value, either through user input or programmatically. If you want your handler to be triggered only when the user changes the input, you should use ionInput event instead.

A bug-around for anybody trapping into this Issue: I found a simple workaround (actually I use it with IonDatetime component): setting the attribute “key” on the component to current value, prevents the element from being updated after IonChange-event. Instead a new instance will be created and therefore the IonChange-event is not called in a loop. 😉 Good luck!

        <IonDatetime
          key={week.toISOString()}
          displayFormat="MMMM YYYY"
          value={format(week, "yyyy-MM")}
          onIonChange={onChange}
        />

This issue has been resolved in this pull request: https://github.com/ionic-team/ionic-framework/pull/25858 and will be available in the next major release (v7) of Ionic.

My workaround consists to check if the select has the focus :

let hasFocus = false;
<IonSelect value={value} onFocus={() => hasFocus = !hasFocus} onIonChange={e => hasFocus && onChange(e.detail.value)}>
...
</IonSelect>

Hello everyone, I’ve created an RFC to discuss changes to the API design that should correct this issue: https://github.com/ionic-team/ionic-framework/discussions/25532

Please share your thoughts and if there is anything we may be missing.

Thanks!

Is there any update on this?

I still cannot find a workaround for this at the moment…

What about leave ionChange as it is, for backward compactibility. And provide new event ‘change’ or something similar with fixed behaviour?

Next step: Events like @change in vuejs can be linked to this new fixed event, but when somebody uses @ionChange, they will be facing same issue till next release of Ionic v6, as mentioned bellow.

Next step: In v6 version this names can be replaced, for smoother transition…

Because it looks, this won’t be fixed in short future.