4

I have the following code

    const SelectSizesDemo = () => {
      const pattern = new RegExp(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i);
      const errorMsg = "please provide valid email!";

      const [emailArr, setEmailArr] = useState([]);
      const [error, setError] = useState(false);

      return (
        <div>
          <Select
            style={{ width: "90%" }}
            mode="tags"
            onChange={(e) => setEmailArr(e)}
          ></Select>
          {error && errorMsg}
        </div>
      );
    };

I am trying to do the following. The user should input some email, if its email is valid with my pattern then I should add it to my emailArr, if it's not correct then I should show the error message errorMsg, clear from the selected items and not allow the user to add it to the array.

In this code, I successfully can add any string to my array, so I want your help to understand how can I check that string with my pattern.

Please help me to resolve this problem.

Thanks

someone
  • 681
  • 4
  • 18
  • updated [code](https://stackblitz.com/edit/react-rrbkw1?file=index.js) but not working correctly – someone Oct 07 '22 at 14:03
  • So do you actually have a "problem" or are you just unsure of how to implement this? – code Oct 11 '22 at 04:34

6 Answers6

6

I've worked on your updated code and figured out what was the problem.

Here is my full code before I start explaining to you what I changed.

Explanations:

  • So first, in order to make the select always have the values of the emailArr, you need to bind it to that state with the value attribute. This way, any change in the emailArr state will be applied to the select values too.

    So simply you add: value = {emailArr} in the select.

  • Second, in the onChange event you get an array in the e object which is the array of the current values that are in the select field. So in order to test the value, you need to check the validation of the current value that was inserted to that array, which is the last one in it.

    In your code you check the validation of the entire array which cause it to not work correctly:

    Your code:

      onChange={(e) => {
          if (pattern.test(e)) {
            setEmailArr(e);
          } else {
            setError(true);
          }
        }}
    

    Should be:

     onChange={(e) => {
          if (e.length !== 0) {//First check if the array is not empty 
    
            const value = e[e.length - 1]; //get the last(current) value from the array
            if (pattern.test(value)) {
              setEmailArr(e);
              setError(false);
            } else {
              setError(true);
            }
    
          }
        }}
    

    So Here, I first check if the e array is not empty. Because if I check the last value of an empty array it will be undefined - which is false, and this will go to the else block and set the error to true, which is wrong. So that's why I start these checks only if there's something to check in the array.

    Next, I check the current value, if it's valid you update the state (which need to be combined with the select) to the new array with the new value, otherwise - it won't. And by the way, I added setError(false) in case that there was an invalid try before and I want to hide the previous error now.

And a note: The emails you enter in the select must be capitalized in order to match the pattern you chose. If you don't want it then just change it to this pattern: /^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,4}$/g.

Result:

ACTION.gif

So that's it. I hope everything was clear, and please check the full code.

Tehila
  • 917
  • 4
  • 19
1

You can validate string with regex using this code :

onChange={(e) => {
              if(pattern.test(e.target.value)){
              setEmailArr(e.target.value)
              }else{
                setError(true)
              }
 }}
Moein Moeinnia
  • 1,945
  • 3
  • 10
  • 26
  • Agree with this solution, but the problem is another thing, for example, if it's incorrect it's not adding to the array but it's added to my selected items. https://ibb.co/HGCWdR8 – someone Oct 07 '22 at 12:07
  • You have to override default events of the `antd` Select component that you are using . try overriding `onBlur` – Moein Moeinnia Oct 07 '22 at 12:34
  • I tried it's not working your suggested way .... here is your [code](https://stackblitz.com/edit/react-g2gszj?file=index.js)... it's adding one time into my array, and for other times it is not added. – someone Oct 07 '22 at 13:46
1

The goal of this solution is to tell antd to use "our" email list instead of using "their" internal list.

onChange is called when a new element is added to the list. Check the last element and see if it's valid and then update your internal email list with antd's email list.

I use Set which automatically handles duplicates, but you could do this with only lists if you prefer.

Whenever the emailSet changes I update the email list alphabetically, but you don't need to do this if you don't want. A simple [...emailSet] is sufficient.

onDeselect seems to be called when the last element is removed, so I just clear the rest of the elements.

const SelectSizesDemo = () => {
  const pattern = new RegExp(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i);

  const [error, setError] = useState(false);
  const [emailSet, setEmailSet] = useState(new Set());
  const emails = useMemo(() => {
    return [...emailSet].sort((a, b) => a.localeCompare(b));
  }, [emailSet]);

  const addEmail = (e) => {
    if(e.length === 0) {
      return;
    }
    const email = e[e.length - 1];
    if (!pattern.test(email)) {
      setError(errorMsg);
      return;
    }
    setEmailSet(new Set(e))
    if (error) {
      setError(false);
    }
  };

  const clearAll = () => {
    setEmailSet(new Set([]));
  };

  return (
    <div>
      <Select
        style={{ width: "90%" }}
        mode="tags"
        onChange={addEmail}
        onDeselect={clearAll}
        value={emails}
      ></Select>
      {error && errorMsg}
    </div>
  );
};

Full solution here.

kemicofa ghost
  • 16,349
  • 8
  • 82
  • 131
1

As per my understanding, You want to test the email based on the input value enter by the user and if its a valid email as per the pattern you want to store that in an array else you want to show the error message. If Yes, Here you go :

To validate an email, You can use the RegEx test() method which executes a search for a match between a regular expression and a specified string. Returns true if the email is valid else returns false.

Live Demo :

const {useState, useCallback} = React;

function Example() {
    const [emailArr, setEmailArr] = useState([]);
    const [error, setError] = useState(false);
    
    function isValidEmail(email) {
      const pattern = new RegExp(/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i);
      return pattern.test(email);
    }
    
    const handleEmailValidation = event => {
      const errorMsg = "please provide valid email!";

      if (!isValidEmail(event.target.value)) {
        setError(errorMsg);
      } else {
        setEmailArr(oldArray => [...oldArray, event.target.value]);
        setError(null);
      }
    };
    
    return (
        <div>
          <input
            id="email"
            name="email"
            onChange={handleEmailValidation}
          />
          {error && <span class="error">{error}</span>}
          
          <div>{emailArr.map(entry =>
            <div>{entry}</div>
          )}
          </div>
        </div>
    );
}

ReactDOM.render(
    <Example />,
    document.getElementById("root")
);
<div id="root"></div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.8.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.8.1/umd/react-dom.production.min.js"></script>
Debug Diva
  • 26,058
  • 13
  • 70
  • 123
0

As answered by Moein, pattern.test(string) is a valid way of checking if the user's input string matches your regex pattern.

Alternatively, you can use String.match(regex) to get an array of matches or null. This can still be used to evaluate truthiness.

Comparison was discussed here: regex.test V.S. string.match to know if a string matches a regular expression

0

you just need to use regex method as pattern.test(yourString)

  • Your answer could be improved with additional supporting information. Please [edit] to add further details, such as citations or documentation, so that others can confirm that your answer is correct. You can find more information on how to write good answers [in the help center](/help/how-to-answer). – Community Oct 16 '22 at 20:56