Availity / availity-reactstrap-validation

Easy to use React validation components compatible for reactstrap.
https://availity.github.io/availity-reactstrap-validation/
MIT License
191 stars 70 forks source link

How to access the errorMessage within an AvGroup? #146

Open amillward opened 5 years ago

amillward commented 5 years ago

Hi,

I'm adding this library to my project, but can't see how to access the errorMessage without using AvField ? (I don't want to use AvField because I have a layout to preserve)

<AvGroup>
  <InputGroup size="sm">
    <InputGroupAddon addonType="prepend">
      <span className="input-group-text">&gt;100</span>
    </InputGroupAddon>
    <AvInput
      type="number"
      name="myNumber"
      value={numAvaility}
      validate={{
        min: {
          value: 100,
          errorMessage: "Must be over 100"
        }
      }}
      onChange={e => setNumAvaility(e.target.value)}
    />
    <AvFeedback>How do I get this message?</AvFeedback>
  </InputGroup>
</AvGroup>

Codesandbox here: https://codesandbox.io/s/broken-smoke-jpbgy

TheSharpieOne commented 5 years ago

You'd have to get getInputState from the FormCtrl context and call it with the specific field's name: FormCtrl.getInputState('myNumber') to get back the validation object which contains errorMessage.

<AvGroup>
  <InputGroup size="sm">
    <InputGroupAddon addonType="prepend">
      <span className="input-group-text">&gt;100</span>
    </InputGroupAddon>
    <AvInput
      type="number"
      name="myNumber"
      value={numAvaility}
      validate={{
        min: {
          value: 100,
          errorMessage: "Must be over 100"
        }
      }}
      onChange={e => setNumAvaility(e.target.value)}
    />
    <AvFeedback>{this.context.FormCtrl && this.context.FormCtrl.getInputState('myNumber').errorMessage}</AvFeedback>
  </InputGroup>
</AvGroup>

AvField is a convenience component for a common layout. If you need a different layout you can basically just copy the existing AvField and modify it in your project to meet your needs.

GoPro16 commented 5 years ago

Alternatively @TheSharpieOne I was also thinking about making an update to allow the user to pass in a name prop on the AvFeedback and then rendering that field's error message by default via the FormCtrl.getInputState like we do for AvField. You see anything wrong with this?

amillward commented 5 years ago

Thank you @GoPro16 . How should the context be passed through? My function looks like this;

function App() {
  const [numAvaility, setNumAvaility] = useState("0");
  return (
    <AvForm>
      <Row>
        <Col xs={{ size: 5, offset: 3 }}>
          <AvGroup>
            <InputGroup size="sm">
              <InputGroupAddon addonType="prepend">
                <span className="input-group-text">&gt;100</span>
              </InputGroupAddon>
              <AvInput
                type="number"
                name="numAvaility"
                value={numAvaility}
                validate={{
                  min: {
                    value: 100,
                    errorMessage: "Must be over 100"
                  }
                }}
                onChange={e => setNumAvaility(e.target.value)}
              />
              <AvFeedback>{this.context.FormCtrl && this.context.FormCtrl.getInputState('numAvaility').errorMessage}</AvFeedback>
            </InputGroup>
          </AvGroup>
        </Col>
      </Row>
    </AvForm>
  );
}

but of course this.context wont work in functional components

TheSharpieOne commented 5 years ago

@GoPro16 That sounds good to me :+1:

matheusb-comp commented 4 years ago

but of course this.context wont work in functional components

@amillward You can access Legacy Contexts in a functional component: React docs

import PropTypes from 'prop-types';

function App(props, context) {
  const [numAvaility, setNumAvaility] = useState("0");
  const validation = (context.FormCtrl) ? context.FormCtrl.getInputState("numAvaility") : {};

  return (
    <AvForm>
      <Row>
        <Col xs={{ size: 5, offset: 3 }}>
          <AvGroup>
            <InputGroup size="sm">
              <InputGroupAddon addonType="prepend">
                <span className="input-group-text">&gt;100</span>
              </InputGroupAddon>
              <AvInput
                type="number"
                name="numAvaility"
                value={numAvaility}
                validate={{
                  min: {
                    value: 100,
                    errorMessage: "Must be over 100"
                  }
                }}
                onChange={e => setNumAvaility(e.target.value)}
              />
              <AvFeedback>{validation.errorMessage || ''}</AvFeedback>
            </InputGroup>
          </AvGroup>
        </Col>
      </Row>
    </AvForm>
  );
}

App.contextTypes = {
  FormCtrl: PropTypes.object.isRequired
}

export default App;