dk4210's avatar

React Async validation

Hello All,

Anyone have any experience with React / async validation? I'm trying to figure out how to do an async validation with JOI.

I can do client side validation, but not sure how to add the async validation. I basically have a required field called package. I want it to server side validation onBlur to see if the package is taken. Can some one give me a hand?

Here's what my code looks like

'use strict';
import axios from 'axios'
import React, { Component } from 'react';
import PropTypes from 'prop-types';
import validation from 'react-validation-mixin';
import strategy from 'joi-validation-strategy';
import Joi from 'joi';
import { Row, Col, Button,  ButtonDropdown, DropdownToggle, DropdownMenu, DropdownItem, Card, CardHeader, CardFooter, CardBody, Form, FormGroup, FormText, Label, Input,
InputGroup, InputGroupAddon, InputGroupButton} from 'reactstrap';

 
class Step1 extends Component {
 constructor(props) {
    super(props)

    // sets state of package name
    this.state = {
      packagename: props.getStore().packagename
      
    };

    this.validatorTypes = {
      packagename: Joi.string().required().min(3).label("The Package Name")
    };

    this.getValidatorData = this.getValidatorData.bind(this);
    this.renderHelpText = this.renderHelpText.bind(this);
    this.isValidated = this.isValidated.bind(this);
  }

  isValidated() {
    return new Promise((resolve, reject) => {
      this.props.validate((error) => {
        if (error) {
          reject(); // form contains errors
          console.log("Error fired");
          return;
        }

        if (this.props.getStore().packagename != this.getValidatorData().packagename) { // only update store of something changed
          this.props.updateStore({
            ...this.getValidatorData(),
            savedToCloud: true // use this to notify step4 that some changes took place and prompt the user to save again
          });  // Update store here (this is just an example, in reality you will do it via redux or flux)
         
          // Ajax send response to server goes here!
          console.log("Validation fired");
        
        }

        resolve(); // form is valid, fire action
        
      });
    });
  }

  getValidatorData() {
    return {
      packagename: this.refs.packagename.value,
    }
  };

  onChange(e) {
      let newState = {};
      newState[e.target.name] = e.target.value;
      this.setState(newState);
  }

  renderHelpText(message, id) {
    return (<div className="val-err-tooltip" key={id}><span>{message}</span></div>);
};

render() {
  // explicit class assigning based on validation
  let notValidClasses = {};
  notValidClasses.packagenameCls = this.props.isValid('packagename') ?
      'no-error col-md-8' : 'has-error col-md-8';

return (
  

    <div className="step step1">
      <div className="row">
      
        <form id="Form" className="form-horizontal">
            <div id="stepscontainer" className="form-group">
            <label className="col-md-12 control-label">
              <h2>Please provide a unique name for the package</h2>
            </label>
            <div className="row content">
              <div className="col-md-12">
                  Give a short name that can identify the package with, using underscore and no spaces.
                  <br /><br />
                     <FormGroup row>
                     <Col xs="12" md="9">
                     <div className={notValidClasses.packagenameCls}>
                     <input
                            ref="packagename"
                            name="packagename"
                            autoComplete="off"
                            type="text"
                            className="form-control"
                            placeholder="Package name"
                            required
                            defaultValue={this.state.packagename}
                            id="packagename"
                            onBlur={this.props.handleValidation('packagename')}
                            onChange={this.onChange.bind(this)}
                            size="145" />
                        {this.props.getValidationMessages('packagename').map(this.renderHelpText)}
                     </div>
                    </Col>
                  </FormGroup>
              
              </div>
              <div className="col-md-12 eg-jump-lnk">
               
              </div>
            </div>
          </div>
          
        </form>
      </div>
      </div>
    )
  }
}

Step1.propTypes = {
  errors: PropTypes.object,
  validate: PropTypes.func,
  isValid: PropTypes.func,
  handleValidation: PropTypes.func,
  getValidationMessages: PropTypes.func,
  clearValidations: PropTypes.func,
  getStore: PropTypes.func,
  updateStore: PropTypes.func
};


export default validation(strategy)(Step1);

Thanks, Dan

0 likes
3 replies
ejdelmonico's avatar

So, you want to query the server to check to see if the package is not in the DB? What is your backend? Are you using Laravel, Node, SSR React or something else?

dk4210's avatar

That's correct I want to see if the package exists on the back end. Back end is going to be developed with Java ( I wish it was laravel). I'm trying to do the front end. If nothing else maybe fake it with a json file or something to prove it works.

Thanks!

ejdelmonico's avatar

Yup, that is a tough one when you don't know what the backend is going to look like or what it actually spits out. Me, I would go with the json file for now and maybe that will give the backend people an idea about how you expect the output to look. The problem is simulating a server-side query. Me, I would look at writing a custom validator using the fetch api with async/await. Not knowing the context of the entire project and what the goals are, it's difficult to make recommendations other than broad ones. If its a long running project, then reducing technical debt is important and would definitely sway towards the fetch api. If you use a promise, that would work as well but would be ideal.

Anyway, what version of React are you using? Aren't you getting a warning from the react tools plugin about your ref? You are using an outdated style for ref.

Please or to participate in this conversation.