Thursday, 28 November 2019

How to manage a multi-step form with React?

Here is the code of my multistep form:

import clsx from 'clsx';
import React from 'react';
import PropTypes from 'prop-types';
import { makeStyles, withStyles } from '@material-ui/styles';
import Step from '@material-ui/core/Step';
import Stepper from '@material-ui/core/Stepper';
import StepLabel from '@material-ui/core/StepLabel';
import StepConnector from '@material-ui/core/StepConnector';
import { Container, Row, Col, Button } from 'react-bootstrap';

import Description from '@material-ui/icons/Description';
import AccountCircle from '@material-ui/icons/AccountCircle';
import DirectionsCar from '@material-ui/icons/DirectionsCar';

import Step1 from '../components/Step1';
import Step2 from '../components/Step2';
import Step3 from '../components/Step3';

const styles = () => ({
  root: {
    width: '90%',
  },
  button: {
    marginRight: '0 auto',
  },
  instructions: {
    marginTop: '0 auto',
    marginBottom: '0 auto',
  },
});

const ColorlibConnector = withStyles({ 
  alternativeLabel: {
    top: 22,
  },
  active: {
    '& $line': {
      backgroundColor: '#00b0ff',
    },
  },
  completed: {
    '& $line': {
      backgroundColor: '#00b0ff',
    },
  },
  line: {
    height: 3,
    border: 0,
    backgroundColor: '#eaeaf0',
    borderRadius: 1,
  },
})(StepConnector);

const useColorlibStepIconStyles = makeStyles({
  root: {
    backgroundColor: '#ccc',
    zIndex: 1,
    color: '#fff',
    width: 50,
    height: 50,
    display: 'flex',
    borderRadius: '50%',
    justifyContent: 'center',
    alignItems: 'center',
  },
  active: {
    backgroundColor: '#00b0ff',
    boxShadow: '0 4px 10px 0 rgba(0,0,0,.25)',
  },
  completed: {
    backgroundColor: '#00b0ff',
  },
});

function ColorlibStepIcon(props) {
  const classes = useColorlibStepIconStyles();
  const { active, completed } = props;

  const icons = {
    1: <AccountCircle />,
    2: <DirectionsCar />,
    3: <Description />,
  };

  return (
    <div
      className={clsx(classes.root, {
        [classes.active]: active,
        [classes.completed]: completed,
      })}
    >
      {icons[String(props.icon)]}
    </div>
  );
}

function getSteps() {
  return ['Dati Assicurato', 'Dati Veicolo', 'Dati Assicurazione'];
}

function getStepContent(step) {
  switch (step) {
    case 0:
      return <Step1/>;
    case 1:
      return <Step2/>;
    case 2:
      return <Step3/>;;
    default:
      return 'Unknown step';
  }
}

class HorizontalLinearStepper extends React.Component {

  constructor(props) {
    super(props);
    this.state = {
      activeStep: 0,
      agencyData: {}
    };
  }

  static propTypes = {
    classes: PropTypes.object,
  };

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

  handleNext = () => {
    const { activeStep } = this.state;
    this.setState({
      activeStep: activeStep + 1,
    });
  };

  handleBack = () => {
    const { activeStep } = this.state;
    this.setState({
      activeStep: activeStep - 1,
    });
  };

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

  logout = () => {
    localStorage.clear();
    this.props.history.push('/');
  }

  render() {
    const { classes } = this.props;
    const steps = getSteps();
    const { activeStep } = this.state;

    return (
      <Container fluid>
        <div className={classes.root}>
          <Stepper alternativeLabel activeStep={activeStep} connector={<ColorlibConnector />}>
            {steps.map((label, index) => {
              const props = {};

              return (
                <Step key={label} {...props}>
                  <StepLabel StepIconComponent={ColorlibStepIcon}>{label}</StepLabel>
                </Step>
              );
            })}
          </Stepper>

          <div>
            {activeStep === steps.length ? (
              <div style=>
                <h1 style=>
                  TERMINATO
                </h1>
                <h4 style=>
                  Tutti gli step sono stati completati con successo! 
                </h4>  
                <h4 style=>  
                  Procedi con la generazione del QR Code.
                </h4>
                <Row style= className='justify-content-center align-items-center text-center'>
                  <Col md=>
                    <Button 
                      style=
                      disabled={activeStep === 0} 
                      onClick={this.handleReset} 
                    >
                      Annulla
                    </Button>
                  </Col>
                  <Col md=>
                    <Button
                        style=
                        onClick={() => console.log('Click')}
                      >
                      Procedi
                    </Button>
                  </Col>
                </Row>
              </div>
            ) : 
            (
              <Container style=>
                <h2 className={classes.instructions}>{getStepContent(activeStep)}</h2>
                <Row className='justify-content-center align-items-center text-center'>
                  <Col md=>
                    <Button 
                      style=
                      disabled={activeStep === 0} 
                      onClick={this.handleBack} 
                    >
                      Indietro
                    </Button>
                  </Col>
                  <Col md=>
                    {
                      activeStep === steps.length - 1 ?
                      <Button
                        style=
                        onClick={this.handleNext}
                      >
                      Finito
                      </Button>
                      :
                      <Button
                        style=
                        onClick={this.handleNext}
                      >
                      Avanti
                      </Button>
                    }
                  </Col>
                </Row>
              </Container>
            )}
          </div>
        </div>
      </Container>
    );
  }
}

export default withStyles(styles)(HorizontalLinearStepper);

It is composed of three steps and at each step I ask for many data.


This is the code of one of the Step (they are all the same, the difference are the contents of the input fields):

import React from 'react';
import { Container, Row, Col, Form } from 'react-bootstrap';

export default function Step2(props) {

  return(
    <Container>
      <Row style= className='h-100 justify-content-center align-items-center'>
        <Col md= className='text-center my-auto'>
          <h3 style=>Dati Veicolo</h3>
          <Form>
            <Form.Row>
              <Form.Group as={Col}>
                <Form.Control
                  type='text' 
                  placeholder='Marca' 
                  required
                />
              </Form.Group>
              <Form.Group as={Col}>
                <Form.Control
                  type='text' 
                  placeholder='Targa' 
                  required
                />
              </Form.Group>
            </Form.Row>
            <Form.Group>
              <Form.Control
                type='text' 
                placeholder='Paese immatricolazione' 
                required
              />
            </Form.Group>
            <h6 style=>Possiede un rimorchio?</h6>              
            <Form.Group>
              <Form.Control
                type='text' 
                placeholder='Targa'
              />
            </Form.Group>
            <Form.Group>
              <Form.Control
                type='text' 
                placeholder='Paese immatricolazione'
              />
            </Form.Group>
          </Form>
        </Col>
      </Row>
    </Container>
  );
}

What I need to do is to check for errors at each step before the users pass to the following one, so that they can start fulfilling the second step of the form only in the case they have completed the first step correctly, and so on ... How can I do this check step by step?

Moreover how can I collect all the data that I ask for in the main component of the form so that I can work with all those data after the users have finished fulfilling the whole form?

At this link there is the example



from How to manage a multi-step form with React?

No comments:

Post a Comment