Как применить проверку формы для React Material-UI TextField и Select?

Я пытаюсь добавить проверку TextField и Select, прежде чем переходить к handleNext(). Вот код (2 компонента):

class Quote extends React.Component {
state = {
    activeStep: 0,
    zipCode: '',
    destination: '',
    sedanPrice: '',
    suvPrice: '',
    labelWidth: 0,
};

getStepContent = (step) => {
    switch (step) {
        case 0:
            return (
                <div>
                    <QuoteForm
                        {...this.state}
                        {...this.state.value}
                        handleChange={this.handleChange}
                    />
                </div>
            )
        case 1:
            return (
                <div>
                    <QuotePrice 
                        {...this.state}
                        {...this.state.value}
                    />
                </div>
            )
        default:
            throw new Error('Unknown step');
    }
}

handleNext = () => {
    this.setState(prevState => ({
        activeStep: prevState.activeStep + 1,
    }));
    switch(this.state.activeStep){
        case 0: 
            // Creates an API call for sedan pricing
            API.getPrice(this.state.zipCode, "sedan" + this.state.destination).then(res => {
                let price = res.data;
                let key = Object.keys(price);
                console.log("Sedan price is $" + price[key]);
                this.setState({sedanPrice: price[key]});
            })
            .catch(err => console.log(err));

            // Creates an API call for SUV pricing
            API.getPrice(this.state.zipCode, "suv" + this.state.destination).then(res => {
                let price = res.data;
                let key = Object.keys(price);
                console.log("SUV price is $" + price[key])
                this.setState({suvPrice: price[key]});
            })
            .catch(err => console.log(err));
        break
        case 1:
            console.log('forward to booking page');
            window.location.href = '/booking';
        break
        default: 
            console.log('over');
    }
};

handleBack = () => {
    this.setState(state => ({
        activeStep: state.activeStep - 1,
        sedanPrice: '',
        suvPrice: '',
        destination: '',
        zipCode: '',
    }));
};

handleReset = () => {
    this.setState({
        activeStep: 0,
    });
};

handleChange = event => {
    const { name, value } = event.target;
    this.setState({
        [name]: value,
    });
};

render() {
    const { classes } = this.props;
    const { activeStep } = this.state;
    const steps = ['Pick Up Address', 'Select Your Vehicle'];

    return (
        <React.Fragment>
            <CssBaseline />
            <main className={classes.layout}>
                <Paper className={classes.paper}>
                    <React.Fragment>
                        {activeStep === steps.length ? (
                            <React.Fragment>
                                <Typography variant="h5" gutterBottom>
                                    Thank you for your interest!
                                </Typography>
                            </React.Fragment>
                            ) : (
                            <React.Fragment>
                                {this.getStepContent(activeStep)}
                                <div className={classes.buttons}>
                                    {activeStep !== 0 && (
                                        <Button onClick={this.handleBack} className={classes.button}>
                                            Back
                                        </Button>
                                    )}
                                    <Button
                                        variant="contained"
                                        color="primary"
                                        onClick={this.handleNext}
                                        className={classes.button}
                                    >
                                        {activeStep === steps.length - 1 ? 'Book Now' : 'Next'}
                                    </Button>
                                </div>
                            </React.Fragment>
                            )}
                    </React.Fragment>
                </Paper>
            </main>
        </React.Fragment>
    );
}

}

QuoteForm.js

export class QuoteForm extends React.Component {

state = {
    zipCode: this.props.zipCode,
    destination: this.props.destination,
}

render() {

    const { classes } = this.props;

    return (
        <React.Fragment>
            <Typography variant="h5" align="center">
                Enter your zip code for a quick quote
            </Typography>
            <Grid container>
                <Grid className={classes.TextField} item xs={12} sm={6}>
                    <TextField
                        required
                        id="zip"
                        name="zipCode"
                        label="Zip / Postal code"
                        fullWidth
                        autoComplete="billing postal-code"
                        value={this.props.zipCode}
                        onChange={this.props.handleChange}
                    />
                </Grid>
                <FormControl xs={12} sm={6} className={classes.formControl}>
                    <Select
                        required
                        value={this.props.destination}
                        onChange={this.props.handleChange}
                        input={<Input name="destination" />}
                        displayEmpty
                        name="destination"
                        className={classes.selectEmpty}
                    >
                        <MenuItem value="">
                            <em>Select Your Airport *</em>
                        </MenuItem>
                        <MenuItem name="SAN" value={"SAN"}>San Diego International Airport</MenuItem>
                        <MenuItem name="LAX" value={"LAX"}>Los Angeles International Airport</MenuItem>
                    </Select>
                </FormControl>
            </Grid>
        </React.Fragment>
    );
}

}

Я пробовал 2 разных способа. Во-первых, с помощью Button disabled и написания функции для обработки проверки и установки disabled в false. Во-вторых, использование пакета npm для обработки проверки. Оба потерпели неудачу, так как я новичок в этом. Любая помощь будет оценена. Заранее спасибо.

1 ответ

Решение

Сделайте следующее:

  • поддерживать логическое состояние, скажем error а также errorMessage
  • в handleNext проверьте введенные значения, установите для ошибки значение false и установите сообщение об ошибке.
  • Для текстового поля пользовательского интерфейса материала используйте error а также helperText реквизиты для установки / отображения ошибок рядом с вашими полями
  • Для выбора материала ui используйте FormControl error поддерживать и обеспечивать label к Select чтобы правильно отображать / устанавливать ошибки рядом с вашими полями
  • не позволяйте пользователю перейти к следующей форме, пока ошибка не будет исправлена.
  • проходят error а также errorMessage к QuoteForm составная часть.

Рабочая копия вашего кода находится здесь, в codeandbox

штат

state = {
    activeStep: 0,
    zipCode: "",
    destination: "",
    sedanPrice: "",
    suvPrice: "",
    labelWidth: 0,
    error: false, //<---- here
    errorMessage: {} //<-----here
  };

handleNext

handleNext = () => {
    let isError = false;
    if (this.state.zipCode.length < 2) {
      isError = true;
      this.setState({
        error: true,
        errorMessage: { zipCode: "enter correct zipcode" }
      });
    } 
    if (this.state.destination === '') {
      isError = true;
      this.setState(prev => ({
        ...prev,
        error: true,
        errorMessage: { ...prev.errorMessage, destination: "enter correct destination" }
      }))
    }  if(!isError){
      //add else if for validating other fields (if any)
      this.setState(prevState => ({
        activeStep: prevState.activeStep + 1,
        error: false,
        errorMessage: {}
      }));
    }
  ...

Текстовое поле Mui

          <TextField
              error={!!this.props.errorMessage.zipCode}
              required
              id="zip"
              name="zipCode"
              label="Zip / Postal code"
              fullWidth
              autoComplete="billing postal-code"
              value={this.props.zipCode}
              onChange={this.props.handleChange}
              helperText={
                this.props.errorMessage.zipCode &&
                this.props.errorMessage.zipCode
              }
            />

Mui Select использовать

<FormControl xs={12} sm={6} error={this.props.error}>
            <Select
              error={!!this.props.errorMessage.destination}
              label="enter cor dest"
              required
              value={this.props.destination}
              onChange={this.props.handleChange}
              input={<Input name="destination" />}
              displayEmpty
              name="destination"
            >
              <MenuItem value="">
                <em>Select Your Airport *</em>
              </MenuItem>
              <MenuItem name="SAN" value={"SAN"}>
                San Diego International Airport
              </MenuItem>
              <MenuItem name="LAX" value={"LAX"}>
                Los Angeles International Airport
              </MenuItem>
            </Select>
            <FormHelperText>
              {this.props.errorMessage.destination}
            </FormHelperText>
          </FormControl>
Другие вопросы по тегам