web-dev-qa-db-fra.com

Validation de formulaire avec Semantic-UI-React

J'utilise les composants officiels Semantic UI React pour créer une application Web. J'ai un formulaire sur ma page d'inscription, qui contient un champ de courrier électronique, un champ de mot de passe et un champ de confirmation du mot de passe.

import {Component} from 'react';
import {Button, Form, Message} from 'semantic-ui-react';
import {signUp} from '../../actions/auth';

class SignUp extends Component {
    constructor(props) {
        super(props);
        this.handleSubmit = this.handleSubmit.bind(this);
    }
    handleSubmit(e, {formData}) {
        e.preventDefault();

        //
        // Potentially need to manually validate fields here?
        //

        // Send a POST request to the server with the formData
        this.props.dispatch(signUp(formData)).then(({isAuthenticated}) => {
            if (isAuthenticated) {
                // Redirect to the home page if the user is authenticated
                this.props.router.Push('/');
            }
        }
    }
    render() {
        const {err} = this.props;

        return (
            <Form onSubmit={this.handleSubmit} error={Boolean(err)}>
                <Form.Input label="Email" name="email" type="text"/>
                <Form.Input label="Password" name="password" type="password"/>
                <Form.Input label="Confirm Password" name="confirmPassword" type="password"/>

                {err &&
                    <Message header="Error" content={err.message} error/>
                }

                <Button size="huge" type="submit" primary>Sign Up</Button>
            </Form>
        );
    }
}

Maintenant, je suis habitué à la bibliothèque de l'interface utilisateur sémantique régulière, qui a un addon Form Validation . Habituellement, je définirais les règles de la sorte dans un fichier JavaScript séparé

$('.ui.form').form({
    fields: {
        email: {
            identifier: 'email',
            rules: [{
                type: 'empty',
                Prompt: 'Please enter your email address'
            }, {
                type: 'regExp',
                value: "[a-z0-9!#$%&'*+/=?^_`{|}~-]+(?:\.[a-z0-9!#$%&'*+/=?^_`{|}~-]+)*@(?:[a-z0-9](?:[a-z0-9-]*[a-z0-9])?\.)+[a-z0-9](?:[a-z0-9-]*[a-z0-9])?",
                Prompt: 'Please enter a valid email address'
            }]
        },
        password: {
            identifier: 'password',
            rules: [{
                type: 'empty',
                Prompt: 'Please enter your password'
            }, {
                type: 'minLength[8]',
                Prompt: 'Your password must be at least {ruleValue} characters'
            }]
        },
        confirmPassword: {
            identifier: 'confirmPassword',
            rules: [{
                type: 'match[password]',
                Prompt: 'The password you provided does not match'
            }]
        }
    }
});

Existe-t-il une méthode similaire utilisant les composants de Semantic UI React pour valider le formulaire? J'ai parcouru la documentation sans succès et il ne semble pas exister de validation à l'aide de cette bibliothèque Semantic UI React. 

Dois-je plutôt valider chaque champ manuellement dans la fonction handleSubmit? Quel est le meilleur moyen de résoudre ce problème? Merci pour l'aide!

7
TFischer

Pour la plupart, vous devez valider les formulaires à la main. Cependant, RSUI inclut quelques outils pour rendre les choses un peu plus faciles, en particulier l’erreur prop sur <Form> et <Form.Input>

Voici un exemple de formulaire que j'ai constitué récemment. Cela pourrait utiliser un peu de refactoring, mais cela fonctionne fondamentalement en liant chaque entrée à une fonction onChange(), puis en rappelant la fonction submit qui contrôle la visibilité de l'écran de chargement et de la partie "Réussite. Merci d'avoir soumis" de la forme. 

export default class MeetingFormModal extends Component {

  constructor(props) {
    super(props)

    this.state = {
      firstName: '',
      lastName: '',
      email: '',
      location: '',
      firstNameError: false,
      lastNameError: false,
      emailError: false,
      locationError: false,
      formError: false,
      errorMessage: 'Please complete all required fields.',
      complete: false,
      modalOpen: false
    }

    this.submitMeetingForm = this.submitMeetingForm.bind(this);
    this.successCallback = this.successCallback.bind(this);
  }


  successCallback() {
    this.setState({
      complete: true
    })
    setTimeout( () => {this.setState({modalOpen: false})}, 5000);
    this.props.hideLoading();
  }

  handleClose = () => this.setState({ modalOpen: false })
  handleOpen = () => this.setState({ modalOpen: true })

  submitMeetingForm() {

    let error = false;

    if (this.state.studentFirstName === '') {
      this.setState({firstNameError: true})
      error = true
    } else {
      this.setState({firstNameError: false})
      error = false
    }
    if (this.state.studentLastName === '') {
      this.setState({lastNameError: true})
      error = true
    } else {
      this.setState({lastNameError: false})
      error = false
    }
    if (this.state.email === '') {
      this.setState({emailError: true})
      error = true
    } else {
      this.setState({emailError: false})
      error = false
    }
    if (this.state.location === '') {
      this.setState({locationError: true})
      error = true
    } else {
      this.setState({locationError: false})
      error = false
    }

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


    let meeting = {
      first_name: this.state.firstName,
      last_name: this.state.lastName,
      email: this.state.email,
      location: this.state.location,

    this.props.createMeeting(meeting, this.successCallback)
    this.props.showLoading();
  }

  capitalize(string) {
    return string.charAt(0).toUpperCase() + string.slice(1);
  }

  render() {
    return(
      <Modal
        trigger={<Button onClick={this.handleOpen} basic color='blue'>Schedule Now</Button>}
        open={this.state.modalOpen}
        onClose={this.handleClose}
        closeIcon={true}
      >
        <Modal.Header>Schedule Your Interview</Modal.Header>
        <Modal.Content>
          {!this.state.complete ?
          <Modal.Description>
            <Form error={this.state.formError}>
              <Form.Group widths='equal'>
                <Form.Field>
                  <Form.Input required={true} onChange={(e) => this.setState({firstName: e.target.value})} label='First Name' placeholder="First Name..." error={this.state.firstNameError}/>
                </Form.Field>
                <Form.Field>
                  <Form.Input required={true} onChange={(e) => this.setState({lastName: e.target.value})} label='Last Name' placeholder="Last Name..." error={this.state.lastNameError}/>
                </Form.Field>
              </Form.Group>
              <Form.Field >
                <Form.Input required={true} onChange={(e) => this.setState({email: e.target.value})} label='Email' placeholder="Email..." error={this.state.emailError}/>
              </Form.Field>
              <Form.Field>
                <Form.Input required={true} onChange={(e) => this.setState({location: e.target.value})} label='Location' placeholder='City, State/Province, Country...' error={this.state.locationError}/>
              </Form.Field>
            </Form>
          </Modal.Description>
          : 
            <div className='modal-complete'>
              <Image src='/images/check.png' />
              <p>Thanks for scheduling a meeting, {this.capitalize(this.state.name)}. We've received your information and we'll be in touch shortly.</p>
            </div>
          }
        </Modal.Content>
        {!this.state.complete ?
        <Modal.Actions>
          <Button color='red' onClick={this.handleClose}>Close</Button>
          <Button positive icon='checkmark' labelPosition='right' content="Submit" onClick={this.submitMeetingForm} />
        </Modal.Actions>
        : null }
      </Modal>
    )
  }
}

J'espère que cela pourra aider!

4
jmknoll

Le code ci-dessous définit essentiellement l'état avec le nom de chaque composant et la valeur associée. (IE, l'état peut ressembler à {marketSide: buy, prix: 50, quantité: 9}. Je saisis également dans le même état les informations d'erreur de formulaire, profitant du comportement par défaut de yup pour ne pas valider les champs non mentionnés par le schéma de validation. . 

Les points importants:

1) L'appel à schema.validate (someObjectToValidate, yupProperties), (où someObjectToValidate est simplement this.state), doit passer {abortEarly: false} en tant qu'objet de propriétés, afin de surcharger le comportement par défaut de yups afin d'arrêter la validation une fois qu'une seule erreur survient été rencontrés, car le composant de message de notre formulaire affiche toutes les erreurs pour l'utilisateur.

2) Si la validation de yup échoue, yup lève une exception. Nous interceptons donc l'exception et sélectionnons les informations d'erreur qui nous intéressent et mettons à jour notre état avec cette erreur.

3) Nous devons utiliser le 'formulaire de rappel' de this.setState (...), puisque setState est asynchrone, de sorte que la validation de l'objet state n'a lieu qu'une fois l'état mis à jour.

4) si la validation réussit, nous effaçons nos tableaux d'erreurs et d'erreurs.

5) Ceci est une solution rapide, je vérifie le tableau errorPaths plusieurs fois à chaque rendu. Il serait préférable de stocker les informations errorPath et error dans un objet json associé au nom du composant, plutôt que dans deux tableaux, pour améliorer la solution actuelle (2 tableaux * N champs * N erreurs potentielles = O (2n ^ 2) performance.

6) Ne tenez pas compte de la notation '<Form.Field control={Radio}>' dans le style long, vous pouvez utiliser le style plus court <Input>, <Button>, <Radio>, etc. Cette syntaxe n'a rien à voir avec la validation. Ignorez également les divs.

import React, { Component } from 'react'
import { Button, Checkbox, Form, Input, Radio, Select, Message,  Label } from 'semantic-ui-react'
import * as yup from 'yup';


const options = [
  { text: 'buy', value: 'buy' },
  { text: 'sell', value: 'sell' },
]

class OrderEntryV3 extends Component {
  state = {
      errorPaths:[],
      errors:[]
  }

  constructor(props){
      super(props);
  }


  schema = yup.object().shape({
    quantity: yup.number().required().positive().integer(),
    price:  yup.number().required().positive(),
    marketSide: yup.string().required(),
    orderType : yup.string().required()
  });



  handleChange = (e, component) => {
      this.setState({[component.name]:component.value}, ()=>this.schema.validate(this.state, {abortEarly:false})
         .then(valid=>this.setState({errorPaths:[], errors:[]})) //called if the entire form is valid
         .catch(err=>this.setState({errors:err.errors, errorPaths: err.inner.map(i=>i.path) }))) //called if any field is invalid
    };


  render() {

    return (
<div id="oeform-content">
    <div id="oeform-left">
      <Form>
          <Form.Field  error={this.state.errorPaths.includes('marketSide')} name="marketSide" control={Select} label='Market side' options={options} placeholder='market side' onChange={this.handleChange}/>
          <Form.Field  error={this.state.errorPaths.includes('quantity')} type='number' name="quantity" control={Input} label='Quantity' placeholder='quantity' onChange={this.handleChange}/>

          <Form.Group>
              <label><b>Order type</b></label>  
        <Form.Field error={this.state.errorPaths.includes('orderType')} >
          <Radio
            label='market'
            name='orderType'
            value='market'
            checked={this.state.orderType === 'market'}
            onChange={this.handleChange}
          />
        </Form.Field>
        <Form.Field error={this.state.errorPaths.includes('orderType')}>
          <Radio
            label='limit'
            name='orderType'
            value='limit'
            checked={this.state.orderType === 'limit'}
            onChange={this.handleChange}
          />
        </Form.Field>
    </Form.Group>
        <Form.Field error={this.state.errorPaths.includes('price')} name='price' control={Input} type='number' label='Price' placeholder='price' onChange={this.handleChange}/>
        <Form.Field control={Button} disabled={!!this.state.errors.length}>Submit</Form.Field>
        <Message visible={!!this.state.errors.length} warning
        header='Please correct the following issues: '
        list={this.state.errors}/>
      </Form>
    </div>
    <div id="oeform-right">
        <p>{JSON.stringify(this.state)}</p>
    </div>
</div>
    )
  }
}

export default OrderEntryV3
0
mancini0

Vous pouvez utiliser le plugin pour la validation . Nom du plugin: formsy-semantic-ui-react

0
Trupti

Dois-je plutôt valider chaque champ à la main dans le descripteur descriptif une fonction?

Triste mais vrai. SUIR n'a pas validation de formulaire à l'heure actuelle. Cependant, vous pouvez utiliser HOC pour travailler avec des formulaires tels que redux-form .

0
Alexander Fedyashov