Search code examples
javascripthtmlreactjsionic-frameworkionic6

IonInput not allowing to conditionally prevent the onChange event


On this StackBlitz project: https://stackblitz.com/edit/node-hxolmq?file=src%2Fmain.tsx

I have the following custom control...

/src/controls/IonInputMagic2.js

import { IonInput } from "@ionic/react";
import { useEffect, useState } from "react";

const IonInputMagic2 = props => {

  const { value, onChange, validityFunc, ...others } = props
  var isValidValue = validityFunc(value);
  const initialValue = (typeof value !== 'undefined' && isValidValue) ? value : '';
  const [ currentValue, setCurrentValue ] = useState(initialValue);

  useEffect(() => {
    setCurrentValue(initialValue);
  }, [initialValue]);

  const handleChange = (e) => {
    var value = e.target.value;
    if (!validityFunc(value)) {
      e.preventDefault();
      return false;
    }
    setCurrentValue(value);
    if (onChange) {
      onChange(e);
    }
  };

  return (
    <IonInput value={currentValue} onChange={handleChange} {...others} />
  );
}

export default IonInputMagic2;

where you can see I use the Ionic control: IonInput.

My problem is: I have a validityFunc(...) that decides if what the user enters is acceptable or not. As per that function, only numeric and even digits are allowed. However, the user can enter whatever character with no restrictions.

I have a similar control: IonInputMagic1 which is very similar, but it uses the HTML built-in element: <input /> instead of the Ionic control: <IonInput />. On that control the user can only enter what is expected: only numeric and even digits.

Here is the difference between those 2 controls (left: works | right: doesn't work)

enter image description here

Here is how I use both controls:

enter image description here

What I need is: To make IonInputMagic2 (which uses: IonInput) work as: IonInputMagic1 where the user can only enter numeric and even digits. This is because the IonInput uses all the styling and scripting of Ionic and I don't want to break all that by using: <input />.

Note: I have detected through the DOM that the IonInput is a wrapper of: <input />.

Any idea on how to achieve that?

If possible, please fork the StackBlitz above and post the link here.

Thanks!


Solution

  • This change did the trick:

    enter image description here

    Here the full code for the component:

    import { IonInput } from "@ionic/react";
    import { useEffect, useState } from "react";
    
    const IonInputMagic2 = props => {
    
      const { value, onChange, validityFunc, ...others } = props
      var isValidValue = validityFunc(value);
      const initialValue = (typeof value !== 'undefined' && isValidValue) ? value : '';
      const [currentValue, setCurrentValue] = useState(initialValue);
    
      useEffect(() => {
        setCurrentValue(initialValue);
      }, [initialValue]);
    
      const handleChange = (e) => {
        var value = e.target.value;
        if (!validityFunc(value)) {
          e.preventDefault();
          e.target.value = currentValue;
          return false;
        }
        setCurrentValue(value);
        if (onChange) {
          onChange(e);
        }
      };
    
      return (
        <IonInput value={currentValue} onIonInput={handleChange} {...others} />
      );
    }
    
    export default IonInputMagic2;