wake-up-neo.com

Formularvalidierung mit Semantic-UI-React

Ich verwende die offiziellen Semantic UI React - Komponenten, um eine Webanwendung zu erstellen. Auf meiner Anmeldeseite befindet sich ein Formular, das ein E-Mail-Feld, ein Kennwortfeld und ein Feld zur Bestätigung des Kennworts enthält.

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>
        );
    }
}

Nun bin ich an die reguläre Semantic UI-Bibliothek gewöhnt, die über ein Form Validation Addon verfügt. Normalerweise würde ich die Regeln wie in einer separaten JavaScript-Datei definieren

$('.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'
            }]
        }
    }
});

Gibt es eine ähnliche Methode, die die Semantic UI React-Komponenten zur Validierung des Formulars verwendet? Ich habe die Dokumentation ohne Erfolg durchsucht und es scheint keine Validierungsbeispiele für diese Semantic UI React-Bibliothek zu geben. 

Muss ich stattdessen jedes Feld in der Funktion handleSubmit von Hand validieren? Was ist der beste Weg, um dieses Problem zu beheben? Danke für die Hilfe!

7
TFischer

In den meisten Fällen müssen Sie Formulare von Hand validieren. RSUI enthält jedoch eine Reihe von Tools, die die Dinge ein bisschen einfacher machen, insbesondere die Fehleranzeige in <Form> und <Form.Input>.

Hier ist ein Beispiel für ein Formular, das ich kürzlich zusammengestellt habe. Es könnte ein bisschen Refactoring sein, aber es funktioniert im Grunde, indem jeder Eingang mit einer onChange()-Funktion an den Status gebunden wird und ein Rückruf an die Submit-Funktion übergeben wird, die die Sichtbarkeit des Ladebildschirms und den Teil "Erfolg. Vielen Dank für das Senden" steuert des Formulars. 

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>
    )
  }
}

Hoffentlich hilft das!

4
jmknoll

Wir haben sogar eine bessere Option, obwohl sie nicht von semantic-ui-react -> Formik + yup bereitgestellt wird
Formik: Hilft bei der Verwaltung des Formularstatus. Yup: Hilft bei der Validierung dieses Status

Ich habe die folgende Komponente, die im Grunde genommen eine Bearbeitungsform ist, die mit semantic-ui-react erstellt wurde.

import React, { Component } from "react";
import { Button, Form, Modal, Message, Divider } from "semantic-ui-react";
import { Formik } from "formik";
import * as yup from "yup";


class EditAboutGrid extends Component {

  render() {
    const {
      userBasic,
      editBasicModal,
      closeModal
    } = this.props;

    return (
      <Formik
        initialValues={{
          firstName: userBasic.firstName,
          lastName: userBasic.lastName,
          bio: userBasic.bio,
        }}
        validationSchema={yup.object().shape({
          firstName: yup
            .string()
            .required("Name cannot be empty"),
          lastName: yup
            .string()
            .required("Name cannot be empty"),
          bio: yup
            .string()
            .max(1000, "Maximum characters exceed 1000")
            .nullable()
        })}
        onSubmit={(values, actions) => {
          //do your stuff here like api calls
        }}
        render={({
          values,
          errors,
          handleChange,
          handleSubmit,
          isSubmitting,
          dirty,
          setFieldValue
        }) => (
          <Modal open={editBasicModal} size="small">
            <Modal.Header>Your basic details</Modal.Header>
            <Modal.Content scrolling>
              {errors.firstName && <Message error content={errors.firstName} />}
              {errors.lastName && <Message error content={errors.lastName} />}
              {errors.bio && <Message error content={errors.bio} />}

              <Form loading={isSubmitting}>
                <Form.Group inline widths="equal">
                  <Form.Input
                    required
                    label="First Name"
                    fluid
                    type="text"
                    name="firstName"
                    value={values.firstName}
                    onChange={handleChange}
                    error={errors.firstName !== undefined}
                  />
                  <Form.Input
                    required
                    label="Last Name"
                    fluid
                    type="text"
                    name="lastName"
                    value={values.lastName}
                    onChange={handleChange}
                    error={errors.lastName !== undefined}
                  />
                </Form.Group>
                <Form.TextArea
                  label="Bio"
                  type="text"
                  name="bio"
                  value={values.bio}
                  onChange={handleChange}
                  rows={3}
                  error={errors.bio !== undefined}
                />
              </Form>
            </Modal.Content>
            <Modal.Actions open={true}>
              <Button
                onClick={() => (dirty ? closeModal(true) : closeModal(false))}>
                Cancel
              </Button>
              <Button
                primary
                type="submit"
                onClick={handleSubmit}
                loading={isSubmitting}
                disabled={isSubmitting || !isEmpty(errors) || !dirty}>
                Update
              </Button>
            </Modal.Actions>
          </Modal>
        )}
      />
    );
  }
}

Und dieses Formular heißt mit:

  <EditAboutGrid
    editBasicModal={this.state.editBasicModal}
    userBasic={this.state.user.basic}
    closeModal={this.closeModal}
  />

initialValues ist der Ort, an dem die Dinge beginnen. Hier geben Sie die Anfangs-/Standardwerte an die Eingaben Ihres Formulars weiter. values (in Form) wählt Datenwerte aus dieser Standardeinstellung aus.

validationSchema ist der Ort, an dem alle Überprüfungen mit yup stattfinden.

onSubmit würde beim Absenden des Formulars aufgerufen.

Die Handhabung von Formularen mit Formik + yup ist sehr einfach. Ich liebe es.

2
TheCoder

Der folgende Code legt im Wesentlichen den Status für jeden Komponentennamen und den zugehörigen Wert fest. (IE, state könnte wie folgt aussehen: {marketSide: buy, price: 50, Quantity: 9}) Ich füge auch die Formularfehlerinformationen in state ein und nutze das Standardverhalten von yup, um Felder, die nicht vom Validierungsschema nicht erwähnt werden, nicht zu überprüfen . 

Wichtige Punkte:

1) Der Aufruf von schema.validate (someObjectToValidate, yupProperties) (wobei someObjectToValidate nur this.state ist) sollte in {abortEarly: false} als Eigenschaftenobjekt übergeben werden, um das Standardverhalten von yups zu überschreiben, sobald ein einzelner Fehler aufgetreten ist aufgetreten, da die Nachrichtenkomponente unseres Formulars dem Benutzer alle Fehler anzeigt.

2) Wenn Ihre Validierung fehlschlägt, löst yup eine Ausnahme aus. Daher werden wir die Ausnahme abfangen und die Fehlerinformationen herausfinden, an denen wir interessiert sind, und den Status mit diesem Fehler aktualisieren.

3) Wir müssen das 'Callback-Formular' von this.setState (...) verwenden, da setState asynchron ist, damit die Überprüfung des Statusobjekts erst erfolgt, nachdem der Status aktualisiert wurde.

4) Wenn die Validierung erfolgreich ist, löschen wir unsere Fehler und errorPath-Arrays.

5) Dies ist eine schnelle Lösung. Ich überprüfe das errorPaths-Array mehrmals bei jedem Rendering. Es ist besser, die errorPath- und Fehlerinformationen in einem json-Objekt zu speichern, das durch den Namen der Komponente anstelle von zwei Arrays codiert ist, um die aktuelle Lösung zu verbessern (2 Arrays * N Felder * N potenzielle Fehler = O (2n ^ 2). Performance.

6) Ignorieren Sie die lange Schreibweise '<Form.Field control={Radio}>'. Sie können den kürzeren <Input>, <Button>, <Radio>, etc-Stil verwenden. Diese Syntax hat nichts mit der Validierung zu tun. Ignorieren Sie auch die 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

Sie können das Plugin zur Validierung verwenden . Plugin-Name: formsy-semantic-ui-react

0
Trupti

Muss ich stattdessen jedes Feld manuell in handleSubmit .__ überprüfen. Funktion?

Traurig aber wahr. SUIR hat derzeit keine Form-Validierung. Sie können jedoch HOC verwenden, um mit Formularen wie redux-form zu arbeiten.

0