0

I am creating a multistep form / wizard with react and Formik. My initial values is an empty array, which I populate with answers from the form. I have this structure, because the data structure must be very specific (not of my choosing). The form is displayed one question at a time, so the user cannot see upcoming questions, only previous answers.

Previous answers should be editable, but in such a way that if an answer is edited, all following answers are reset and the user must start over with the form from the point where the form was edited. Hence, I need to get the index of the question where the value is being updated and remove all following values. Basically, I need to do:

const newArray = array.splice(index, array.length)

...but in Formik. Is this possible?

I have looked at enableReinitialize but I only need to reset part of my form, at a given index.
All I can find in the docs are ways of removing or inserting values, but not to reset.

I have also tried versions of setFieldValues('answers', []) but haven't gotten it to work.
All suggestions are much appreciated.

Here is my form component:

// lib
import { Formik, Form, Field, FieldArray } from 'formik';
import { motion, AnimatePresence, useScroll } from "framer-motion";

// components
import Question from './Question'
import ProgressBar from './ProgressBar'

// utils
import * as constants from '../Utils/constants';


const WizardBase = (props) => {

    const ref = React.useRef(null);

    const questionsToShow = 1;
    const [next, setNext] = useState(questionsToShow - 1);
    const [questions, setQuestions] = useState([]);
    const [question, setQuestion] = useState([]);


    const handleMoreQuestions = (index) => {
        setNext(next + questionsToShow);
    };

    useEffect(() => {
        props.loadQuestions();
    }, []);

    const questionGroups = props.wizardData.questions;
  
    useEffect(() => {
        if (questionGroups) {
            questionGroups.map((sections, i) => {

                sections.questions.map((question, index) => {
                    setQuestions(questions => [...questions, question]);
                })
            })
        }

    }, [questionGroups])

    useEffect(() => {
        if (questions.length > 0) {
            questions.map((question, i) => {
                setQuestion(question => [...questions, question])
            })
        }
    }, [questions])

    return (
        <div className="pension-wizard-block">Pension insurance

            <nav className="top-nav">
                <ProgressBar total={questions.length} />
            </nav>
              

            <Formik initialValues={constants.initialValues}
                onSubmit={(values) => { console.log(values) }}>
               
                <Form>
     
                     <div className='pension-wizard-block__question'
                           ref={ref}
                        >Välkommen
                            <button onClick={handleMoreQuestions}>Börja</button>
                     </div>
    
                    <FieldArray name="Answers">
                        {({ insert, remove, push }) => (
                            
                            question && question.length > 0 && question.slice(0, next).map((q, index) => (
                                <Question
                                    key={q.id}
                                    index={index}
                                    legend={`Fråga ${index + 1}`}
                                    question={q.questionText}
                                    type='radio'
                                    labels={q.options}
                                    options={q.options}
                                    id={`Answers.${index}.QuestionId`}
                                    questionId={q.id}
                                    name={`Answers.${index}.Answer`}
                                    handleMoreQuestions={handleMoreQuestions}
                                    total={questions.length}
                                    />
                                ))
                            
                            
                       )}
                    </FieldArray>

                            <button type="submit">Submit</button>
                        </Form>
                </Formik>

        </div>
     )
}

This is my question component:


// lib 
import { motion, useViewportScroll } from 'framer-motion';
import { throttle } from 'lodash';

// components
import QuestionInput from './QuestionInput'

const Question = ({
    type,
    name,
    legend,
    checked,
    options,
    question,
    id,
    questionId,
    handleMoreQuestions,
    index,
    total
}) => {


    const [answered, setAnswered] = useState(null);
    const [scrollingUp, setScrollingUp] = useState(false)

    // check scroll direction
    let { scrollY } = useViewportScroll();

    const update = useMemo(() => throttle((latest) => {
        if (latest < 0) return;

        let isScrollingDown = scrollY.getPrevious() - latest < 0;
        let scrollDirection = isScrollingDown ? "down" : "up";
        setScrollingUp(isScrollingDown)

    }, 100), [scrollY]);

    useEffect(() => {
        scrollY.onChange(update);
    }, [update]);

    // scroll effect on answer
    const refs = useRef([]);

    useEffect(() => {
        if (total) {
            if (refs.current[index] && total >= index + 1) {
                refs.current[index].scrollIntoView({ behavior: "smooth" });
            } else {
                console.log("end");
            }
        }
    }, [index]);

    // height animation on answer
    const variant = {
        open: {
            height: '80vh',
        },
        closed: {
            height: '100%',
        }
    }


    return (
        <motion.div
            animate={answered ? "closed" : "open"}
            variants={ variant }
            className={`pension-wizard-block__question ${answered !== null ? "answered" : ""}`}
            ref={(element) => (refs.current[index] = element)}
        >
            <fieldset className="pension-wizard-block__question__inner">
                <legend>{legend}</legend>

                <p>{question}</p>
                {options && options.length > 0 && options.map((option, index) => (
                    <QuestionInput
                        key={index}
                        handleMoreQuestions={handleMoreQuestions}
                        index={index}
                        questionId={questionId}
                        id={id}
                        type={type}
                        name={name}
                        label={option.text}
                        handleAnswered={setAnswered}
                        total={total}
                    />
                ))}
            </fieldset>
        </motion.div>    
        )
}

export default Question;

0 Answers0