Ad

Success Message Continues Fire Despite Error State In Semantic-React-UI Form

I am trying to get the appropriate messages to fire depending on the state of my form component for front end validation on form submit.

One of the main validations I'm working on is checking if a email exists and if so one should continue to see the error message fire. If it doesn't exist in the database a success message should fire; And of course if the other validations pass!.

I am using Semantic-UI React Forms to help with validation.

These are the key and values which I have set on the state object in my form component:

this.state = {
  fadeUp: 'fade up',
  duration: 500,
  username: '',
  password: '',
  usernameError: false,
  passwordError: false,
  formSuccess: false,
  formError: false,
  userNameDup: false,
}

This is my submit handler which fires upon submit:

handleSubmit(event) {
 event.preventDefault();
 var error = false

 var { username, password, userNameDup } = this.state

 var mailFormat = /^(([^<>()\[\]\\.,;:\[email protected]"]+(\.[^<>()\[\]\\.,;:\[email protected]"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/


if (!username.match(mailFormat)) {
  this.setState({ usernameError: true });
  error = true;
} else {
  this.setState({ usernameError: false });
}

if (password.length < 8) {
  this.setState({ passwordError: true });
  error = true;
} else {
  this.setState({ passwordError: false })
}

if (error) {
  this.setState({ formSuccess: false });
  return;
} else {
  this.setState({ formSuccess: true });
}

window.fetch('http://localhost:8016/users/registration', {
  method: 'POST',
  headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
  body: JSON.stringify({ username_email: username, password: password })
})
  .then(this.handleErrors)
  .then(function (response) {
    console.log(`response ${response}`)
    return response.json()
  }).then(function (data) {

    console.log('User created:', data)
  }).catch(function (error) {
    console.log(error);
  });

   setTimeout(() => { this.setState({ username: '', password: '' }) })

 }

handleErrors(response) {
  if (!response.ok) {
    if (response.status === 409) {
      console.log("response.status ", response.status);
      this.setState({
      userNameDup: true, formError: true, formSuccess:false
    });
    return;
  }
 } else {
  this.setState({
    userNameDup: false, formError:false
  })
 }
   return response;
 }

This is a portion of the form view/markup:

  {console.log("formSuccess 1", formSuccess)}

<Form size='large'
  onSubmit={this.handleSubmit}
  error={userNameDup || formError}>
  {console.log("formSuccess 2", formSuccess)}

  <Segment stacked>
    <Form.Input fluid icon='user'
      iconPosition='left'
      placeholder='E-mail address, e.g. [email protected]'
      name='username'
      value={username}
      onBlur={this.handleBlur}
      onChange={this.handleChange}
      error={usernameError}
    />

    <Transition visible={usernameError}
      animation='scale'
      duration={duration}>
      <Message error content='username_Email is in incorrect format e.g. [email protected]' />
    </Transition>

    <Form.Input fluid icon='lock'
      iconPosition='left'
      placeholder='Password'
      name='password'
      value={password}
      onBlur={this.handleBlur}
      onChange={this.handleChange}
      error={passwordError}
    />

    <Transition visible={passwordError}
      animation='scale'
      duration={duration}>
      <Message error content='Password needs to be greater than eight characters.' />
    </Transition>

    <Button color='teal'
      fluid size='large'
      disabled={!username || !password}>
      Register
      {/* {isLoggedIn ? `Register` : `Log-in`} */}
    </Button>

    <Transition visible={userNameDup || formError}
      unmountOnHide={true}
      animation='scale'
      duration={duration}>
      <Message
        error
        centered="true" header='This email exists.'
        content='Please re-enter another email address.' />
    </Transition>

    <Transition visible={formSuccess}
      unmountOnHide={true}
      animation='scale'
      duration={duration}>
      <Message
        success
        header='Your user registration was successful.'
        content='You may now log-in with the username you have chosen.' />
    </Transition>
  </Segment>
</Form>

I supplied a gif and you can see the formSuccess key jumps to true for a second which causes the problem. But I thought my handleError is taking care of that on submit?

handleError again:

 handleErrors(response) {
    if (!response.ok) {
      if (response.status === 409) {
        console.log("response.status ", response.status);
        this.setState({
          userNameDup: true, formError: true, formSuccess:false /* why doesn't it stay falsey? */
        });
        return;
      }
    } else {
      this.setState({
        userNameDup: false, formError:false
      })
    }
    return response;
  }

Excerpt from handle submit:

window.fetch('http://localhost:8016/users/registration', {
  method: 'POST',
  headers: { 'Accept': 'application/json', 'Content-Type': 'application/json' },
  body: JSON.stringify({ username_email: username, password: password })
})
  .then(this.handleErrors) /* Shouldn't this be where it changes to false? */
  .then(function (response) {
    console.log(`response ${response}`)
    return response.json()
  }).then(function (data) {

    console.log('User created:', data)
  }).catch(function (error) {
    console.log(error);
  });

Also shouldn't the message animate every time one would hit register?

Please help!!! And thank you!

Ad

Answer

if (error) {
    this.setState({ formSuccess: false });
    return;
} else {
    this.setState({ formSuccess: true });
}

When you hit submit, the initial value for the error variable is false, so it changes the formSuccess state to true until the promise is resolved - when handleErrors is called and changes it back to false. You should only set formSuccess to true after you fetch the data from db, that is, inside .then() block to avoid async issues.

One approach to solving it is to display the success message after you fetched the data and validated the user is new like so:

handleErrors(response) {
  if (!response.ok) {
    if (response.status === 409) {
      console.log("response.status ", response.status);
      this.setState({
      userNameDup: true, formError: true, formSuccess:false
    });
    return;
  }
 } else {
  this.setState({
    userNameDup: false, formError:false, formSuccess: true
  })
 }
   return response;
 }

And then your frontend validation is restricted to only showing the error message.

if (!username.match(mailFormat)) {
  this.setState({ usernameError: true, formSuccess: false } });
} else {
  this.setState({ usernameError: false });
}

if (password.length < 8) {
  this.setState({ passwordError: true, formSuccess: false } });
} else {
  this.setState({ passwordError: false })
}
Ad
source: stackoverflow.com
Ad