2

Forgive me I've been through a lot of the existing questions around on this topic without success.

I have a filter dialog with several input fields (child components) and a submit button. I want the submit button to be disabled if a validation message exists on one of the child components.

Child (simplified):

const TextSearch: FC<TextSearchProps> = memo((props) => {

  const [validationMessage, setValidationMessage] =  useState('')

  const onTextChange = (e: React.FormEvent<HTMLInputElement>) => {
    const input = e.currentTarget.value

    if(input && !checkNumericOnly(input)) {
      setValidationMessage('Only numbers allowed')
    } else {
      setValidationMessage('')
    }

return (
  <div className={classes.textSearch}>
    <InputText
      className={validationMessage ? 'p-invalid' : ''}
      onChange={onTextChange}
    />
    <div className={classes.invalid}>{validationMessage}</div>
  </div>
)

Parent:

const AdvancedSearch: FC<SearchProps> = memo(_props => {
    const dispatch: AppDispatch = useDispatch()

    const data = useSelector(selectSearchData())

    const [validInput, setValidInput] = useState(true) // this is what I'm trying to set

How do I setValidInput based on whether the child validationMessage is true?

Have tried a function in the parent dialog:

function handleValidInput(valid: boolean) {
    setValidInput(valid)
}

But have not been able to figure out how to call it from the child.

1 Answer 1

1

You should pass your setState function to your children and then update the state there:

In parent (AdvancedSearch):

const [validInput, setValidInput] = useState(true);
return (
  <TextSearch setValidInput={setValidInput} />
)

In child (TextSearch):

const onTextChange = (e: React.FormEvent<HTMLInputElement>) => {
  const input = e.currentTarget.value
  if(input && !checkNumericOnly(input)) {
    setValidationMessage('Only numbers allowed');
    props.setValidInput(false);
  } else {
    setValidationMessage('');
    props.setValidInput(true);
  }
}
return (
  <div className={classes.textSearch}>
    <InputText
      className={validationMessage ? 'p-invalid' : ''}
      onChange={onTextChange}
    />
    <div className={classes.invalid}>{validationMessage}</div>
  </div>
)
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks so much for your quick response. Does the <InputText> element have to be moved to the parent? I have several different child components that are all search/filter fields. Also I have a TS2552: Cannot find name 'onTextChange'. Did you mean 'onchange'? error with line 5 of the suggested parent.
You're welcome. Please pick my answer as the correct answer if it's possible. Thanks.
I can't find a way to make your solution work unfortunately :(
Can someone explain to me how the child can have a onTextChange method without returning an <InputText> element. What would the child return in the suggested solution? Thanks.
@melable Sorry, my mistake. I updated my answer. Please test the new one.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.