使用Semantic-UI-React

时间:2017-01-18 16:15:16

标签: javascript validation reactjs semantic-ui semantic-ui-react

我正在使用官方Semantic UI React组件来创建Web应用程序。我的注册页面上有一个表单,其中包含电子邮件字段,密码字段和确认密码字段。

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

现在,我已经习惯了常规的语义UI库,它有一个Form Validation addon。通常,我会在单独的JavaScript文件中定义规则

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

是否有类似的方法使用Semantic UI React组件验证表单?我搜索了文档但没有任何成功,似乎没有使用此Semantic UI React库进行验证的示例。

我是否需要在handleSubmit函数中手动验证每个字段?解决此问题的最佳方法是什么?谢谢你的帮助!

9 个答案:

答案 0 :(得分:5)

在大多数情况下,您必须手动验证表单。但是,RSUI包含一些工具可以使事情变得更容易一些,特别是<Form><Form.Input>上的错误提示

这是我最近放在一起的表格示例。它可以使用一些重构,但它基本上是通过使用onChange()函数将每个输入绑定到状态,并将回调传递给提交函数,该函数控制加载屏幕的可见性和“成功。谢谢你提交“表格的一部分。

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

希望有所帮助!

答案 1 :(得分:1)

我们甚至有一个更好的选择,尽管语义ui-react没有提供-> Formik + yup
Formik:帮助管理表单状态 是的:有助于验证该状态

我有以下组件,基本上是使用语义UI反应创建的编辑表单。

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

此表单的调用方式为:

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

initialValues是事物开始的地方。在这里,您将初始/默认值传递给表单的输入。 values(以表格形式)将从默认值中选择数据值。

validationSchema是使用yup

进行所有验证的地方

onSubmit将在表单提交时被调用。

使用Formik + yup处理表单非常简单。我很喜欢。

答案 2 :(得分:0)

  

我是否需要在handleSubmit中手动验证每个字段   功能

很伤心,但也是如此。 SUIR doesn't have目前正在进行验证。但是,您可以使用HOC来处理redux-form等表单。

答案 3 :(得分:0)

您可以使用插件进行验证。 插件名称:formsy-semantic-ui-react

答案 4 :(得分:0)

以下代码本质上将状态设置为每个组件名称和关联值。 (即,状态可能看起来像{marketSide:buy,价格:50,数量:9}我也将表单错误信息也填充到状态中,利用yup的默认行为来不验证验证模式未提及的字段

重要点:

1)对schema.validate(someObjectToValidate,yupProperties)的调用(其中someObjectToValidate只是this.state),应传入{abortEarly:false}作为属性对象,以覆盖yups默认行为以在一次由于表单的消息组件向用户显示了所有错误,因此遇到了一个错误。

2)如果yup验证失败,则yup会引发异常,因此我们会捕获该异常并提取我们感兴趣的错误信息,并使用此错误更新状态。

3)由于setState是异步的,因此必须使用this.setState(...)的“回调形式”,以便仅在状态更新后进行状态对象的验证。

4)如果yup验证成功,我们将清除错误和errorPath数组。

5)这是一个快速的解决方案,我在每个渲染器上多次检查errorPaths数组。最好将errorPath和错误信息存储在以组件名称为键的json对象中,而不是存储在两个数组中,以改善当前解决方案的(2个数组* N个字段* N个潜在错误= O(2n ^ 2)性能。

6)忽略长样式'<Form.Field control={Radio}>'的表示法,可以使用较短的<Input>, <Button>, <Radio>,等样式。此语法与验证无关。还要忽略div。

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

答案 5 :(得分:0)

我知道这已经有几年历史了,它并不是一个完整的解决方案,但是今天遇到的任何人都可以找到有用的方法,因为我一直在寻找相同的方法并遇到了这个问题。尽管语义UI反应没有我可以找到的表单验证,但是它具有显示表单验证错误的好方法。您仍然必须自己进行验证。有关如何显示验证错误的示例,请参见semantic-ui-react forms documentation page。它还具有显示成功消息的功能。我创建了example,说明如何根据状态控制错误消息。在此示例中,您可以使用“显示性别错误”复选框在“性别”输入上切换错误消息。

答案 6 :(得分:0)

我知道这个问题已经有好几年了,但这是我在使用(相对)较新的React功能组件和Hooks API时遇到的困难。就我而言,我只是想验证用户输入的内容是有效的电子邮件地址。我最终在下面的代码中得到了想要的行为。

import React, {useState} from 'react';
import { Form } from 'semantic-ui-react'
import EmailValidator from 'email-validator';


function MyFormComponentExample() {
    const [emailInput, setEmail] = useState("");
    const [validEmail, validateEmail] = useState(true);

    return (
    <Form>
        <Form.Input
            icon='envelope'
            iconPosition='left'
            label='Email'
            placeholder='Email Address'
            required
            value={emailInput}
            onChange={e => {
                setEmail(e.target.value);                               
                validateEmail(EmailValidator.validate(e.target.value));
            }}
            error={validEmail ? false : {
                content: 'Please enter a valid email address.',
                pointing: 'below'
            }}
        />
    </Form>
    );
}

export default MyFormComponentExample;

一旦我弄清楚了,我认为这种结构很简单,但是如果有人对执行此操作的更好模式或方法有反馈,我将很乐意听!

答案 7 :(得分:0)

您可以使用Formik进行验证。

我创建了一个库来绑定Formik和语义UI React。

https://github.com/JT501/formik-semantic-ui-react

一个简单的例子: Codesandbox

答案 8 :(得分:-1)

对于语义UI中的验证形式,您无需任何插件即可轻松实现

<Form.Field
      id='form-input-control-project-name'
      control={Input}
      label='Project Name'
      placeholder='Project name'
      onChange={this.handleChange}
      error={this.state.projectName}
    />

this.state.projectName 在此变量中,您必须存储错误/错误消息

如果值为假不显示错误否则显示错误