如何验证材料ui步进器中的每个表单步骤?

时间:2020-02-02 18:40:32

标签: reactjs material-ui react-final-form

下面是典型的材料UI步进器。

  export default function HorizontalLinearStepper() {
    const classes = useStyles();
    const [activeStep, setActiveStep] = React.useState(0);
    const [skipped, setSkipped] = React.useState(new Set());
    const steps = getSteps();

    const isStepOptional = step => {
        return step === 1;
    };

    const isStepSkipped = step => {
        return skipped.has(step);
    };

    const handleNext = () => {
    let newSkipped = skipped;
    if (isStepSkipped(activeStep)) {
        newSkipped = new Set(newSkipped.values());
        newSkipped.delete(activeStep);
    }

    setActiveStep(prevActiveStep => prevActiveStep + 1);
    setSkipped(newSkipped);
};

const handleBack = () => {
    setActiveStep(prevActiveStep => prevActiveStep - 1);
};

const handleSkip = () => {
    if (!isStepOptional(activeStep)) {
        // You probably want to guard against something like this,
        // it should never occur unless someone's actively trying to break something.
        throw new Error("You can't skip a step that isn't optional.");
    }

    setActiveStep(prevActiveStep => prevActiveStep + 1);
    setSkipped(prevSkipped => {
        const newSkipped = new Set(prevSkipped.values());
        newSkipped.add(activeStep);
        return newSkipped;
    });
};

const handleReset = () => {
    setActiveStep(0);
};

return (
    <div className={classes.root}>
        <Stepper activeStep={activeStep}>
            {steps.map((label, index) => {
                const stepProps = {};
                const labelProps = {};
                if (isStepOptional(index)) {
                    labelProps.optional = <Typography variant="caption">Optional</Typography>;
                }
                if (isStepSkipped(index)) {
                    stepProps.completed = false;
                }
                return (
                    <Step key={label} {...stepProps}>
                        <StepLabel {...labelProps}>{label}</StepLabel>
                    </Step>
                );
            })}
        </Stepper>
        <div>
            {activeStep === steps.length ? (
                <div>
                    <Typography className={classes.instructions}>
                        All steps completed - you&apos;re finished
                    </Typography>
                    <Button onClick={handleReset} className={classes.button}>
                        Reset
                    </Button>
                </div>
            ) : (
                <div>
                    <div className={classes.instructions}>{getStepContent(activeStep)}</div>
                    <div>
                        <Button disabled={activeStep === 0} onClick={handleBack} className={classes.button}>
                            Back
                        </Button>
                        {isStepOptional(activeStep) && (
                            <Button
                                variant="contained"
                                color="primary"
                                onClick={handleSkip}
                                className={classes.button}
                            >
                                Skip
                            </Button>
                        )}

                        <Button
                            variant="contained"
                            color="primary"
                            onClick={handleNext}
                            type="submit"
                            className={classes.button}
                        >
                            {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
                        </Button>
                    </div>
                </div>
            )}
        </div>
    </div>
    );
}

这是我为选择步骤创建的功能

function getStepContent(step) {
    switch (step) {
        case 0:
            return <Step1/>;
        case 1:
            return <Step2/>;
        case 2:
            return 'This is the bit I really care about!';
        default:
            return 'Unknown step';
    }
}

Step1和Step2是内部具有2种形式的组件,带有react-final-form

import React, { Component } from 'react';
import { Form } from 'react-final-form';
import initialValuesCreator from './creationMethods/initialValuesCreator';
import { validationCreator } from './creationMethods/validationSchemaCreator';

class CustomValidationForm extends Component {

    render() {
        const {
            config ,children, submit = () => {}
        } = this.props;

        return (
            <Form
                onSubmit={(event) => {
                    submit(event);
                }}
                initialValues={initialValuesCreator(config)}
                validate={values => validationCreator(values, config)}
                render={({handleSubmit}) => (
                    <form noValidate autoComplete={'off'} onSubmit={handleSubmit}>
                        {children}
                    </form>
                )}
            />
        )
    }
}

问题来了。材质ui步进器具有handleNext功能。它是我为每一步提交的内容。每个步骤都是经过验证的某种形式。当用户在步骤1上并按“提交”时,我想向他显示输入错误(需要某些操作等),并防止跳转到下一步。第1步可以有多个小表格,因此在按下handleNext时应验证所有表格。

2 个答案:

答案 0 :(得分:3)

我也在处理它 我终于做了解决的事情:

  1. 用表格(而不是div)包装页面
  2. 使用“ useRef” react钩子设置对表单的引用
  3. 在“ handleNext”方法上检查该表单是否有效,如果无效,则返回。对表单对象的访问是通过useRef钩子实现的,而有效性检查是通过函数'myForm.current.checkValidity()'
  4. 进行的。

请尝试一下,让我知道它是否对您有用:

export default function HorizontalLinearStepper() {
    const classes = useStyles();
    const [activeStep, setActiveStep] = React.useState(0);
    const [skipped, setSkipped] = React.useState(new Set());
    const steps = getSteps();

    const myForm = React.useRef(null);

    const isStepOptional = step => {
        return step === 1;
    };

    const isStepSkipped = step => {
        return skipped.has(step);
    };

    const handleNext = () => {
        if (!myForm.current.checkValidity()) {
           return;
        }
        let newSkipped = skipped;
        if (isStepSkipped(activeStep)) {
            newSkipped = new Set(newSkipped.values());
            newSkipped.delete(activeStep);
        }
    
        setActiveStep(prevActiveStep => prevActiveStep + 1);
        setSkipped(newSkipped);
    };
    
    const handleBack = () => {
        setActiveStep(prevActiveStep => prevActiveStep - 1);
    };
    
    const handleSkip = () => {
        if (!isStepOptional(activeStep)) {
            // You probably want to guard against something like this,
            // it should never occur unless someone's actively trying to break something.
            throw new Error("You can't skip a step that isn't optional.");
         }
     
        setActiveStep(prevActiveStep => prevActiveStep + 1);
        setSkipped(prevSkipped => {
            const newSkipped = new Set(prevSkipped.values());
            newSkipped.add(activeStep);
            return newSkipped;
        });
    };

    const handleReset = () => {
        setActiveStep(0);
    };

return (
    <div className={classes.root}>
        <Stepper activeStep={activeStep}>
            {steps.map((label, index) => {
                const stepProps = {};
                const labelProps = {};
                if (isStepOptional(index)) {
                    labelProps.optional = <Typography variant="caption">Optional</Typography>;
                }
                if (isStepSkipped(index)) {
                    stepProps.completed = false;
                }
                return (
                    <Step key={label} {...stepProps}>
                        <StepLabel {...labelProps}>{label}</StepLabel>
                    </Step>
                );
            })}
        </Stepper>
        <form action="/" method="POST" ref={myForm}>
            {activeStep === steps.length ? (
                <div>
                    <Typography className={classes.instructions}>
                        All steps completed - you&apos;re finished
                    </Typography>
                    <Button onClick={handleReset} className={classes.button}>
                        Reset
                    </Button>
                </div>
            ) : (
                <div>
                    <div className={classes.instructions}>{getStepContent(activeStep)}</div>
                    <div>
                        <Button disabled={activeStep === 0} onClick={handleBack} className={classes.button}>
                            Back
                        </Button>
                        {isStepOptional(activeStep) && (
                            <Button
                                variant="contained"
                                color="primary"
                                onClick={handleSkip}
                                className={classes.button}
                            >
                                Skip
                            </Button>
                        )}

                        <Button
                            variant="contained"
                            color="primary"
                            onClick={handleNext}
                            type="submit"
                            className={classes.button}
                        >
                            {activeStep === steps.length - 1 ? 'Finish' : 'Next'}
                        </Button>
                    </div>
                </form>
            )}
        </div>
    </div>
    );
}

答案 1 :(得分:0)

我想出的进行逐步验证的最佳方法是将表单分解成小表单,并让控制器组件将所有表单值组合在一起,就像Wizard Form Example中一样。