Skip to content

How to triggter validation in wizard when cliking on Next button?

In Laravel 8 app which uses vuejs and jquery I found wizard made with html like :

<div class="content__inner">
    <div class="ccontainer overflow-hiddenn">
        <!--multisteps-form-->
        <div class="multisteps-form">
            <div class="multisteps-form__progress">
                <button
                    class="multisteps-form__progress-btn js-active"
                    type="button"
                    title="Add Project Info"
                >
                    Project Info
                </button>
                <button
                    class="multisteps-form__progress-btn"
                    type="button"
                    title="Add Product"
                >
                    Product Details 22222
                </button>
                <button
                    class="multisteps-form__progress-btn"
                    type="button"
                    title="Project Budget & Diagram"
                >
                    Project Budget & Diagram
                </button>
                <button
                    class="multisteps-form__progress-btn"
                    type="button"
                    title="Video & Website Link"
                >
                    Video & Website Link
                </button>
            </div>

            <form class="multisteps-form__form">
                <!--single form panel-->
                <div
                    class="multisteps-form__panel shadow p-4 rounded bg-white js-active"
                    data-animation="scaleIn"
                >
                    <!-- <h3 class="multisteps-form__title">Your User Info</h3> -->
                    <div class="multisteps-form__content">
                        <div class="row">
                            <div class="col-xl-4">
                                <div class="submit-field">
                                    <h5>
                                        Project Name
                                        <span>*</span>
                                    </h5>
                                    <input
                                        type="text"
                                        class="with-border"
                                        id="name_project"
                                        v-model="project.name"
                                    />
                                </div>
                            </div>

                            <div class="col-xl-4">
                                <div class="submit-field">
                                    <h5>
                                        Choose Categories
                                        <span>*</span>
                                    </h5>
                                    <b-form-select
                                        class="tzselectpicker"
                                        v-model="project.category"
                                    :options="project_category"
                                ></b-form-select>
                            </div>
                        </div>

and inited js function

setStepForm() {
    //DOM elements
    const DOMstrings = {
        stepsBtnClass: "multisteps-form__progress-btn",
        stepsBtns: document.querySelectorAll(
            `.multisteps-form__progress-btn`
        ),
        stepsBar: document.querySelector(".multisteps-form__progress"),
        stepsForm: document.querySelector(".multisteps-form__form"),
        stepsFormTextareas: document.querySelectorAll(
            ".multisteps-form__textarea"
        ),
        stepFormPanelClass: "multisteps-form__panel",
        stepFormPanels: document.querySelectorAll(
            ".multisteps-form__panel"
        ),
        stepPrevBtnClass: "js-btn-prev",
        stepNextBtnClass: "js-btn-next"
    };
    console.log(" setStepForm DOMstrings::");
    console.log(DOMstrings);

    //remove class from a set of items
    const removeClasses = (elemSet, className) => {
        elemSet.forEach(elem => {
            elem.classList.remove(className);
        });
    };

    //return exect parent node of the element
    const findParent = (elem, parentClass) => {
        let currentNode = elem;
        while (!currentNode.classList.contains(parentClass)) {
            currentNode = currentNode.parentNode;
        }
        return currentNode;
    };

    //get active button step number
    const getActiveStep = elem => {
        return Array.from(DOMstrings.stepsBtns).indexOf(elem);
    };

    //set all steps before clicked (and clicked too) to active
    const setActiveStep = activeStepNum => {
        //remove active state from all the state
        removeClasses(DOMstrings.stepsBtns, "js-active");
        //set picked items to active
        DOMstrings.stepsBtns.forEach((elem, index) => {
            if (index <= activeStepNum) {
                elem.classList.add("js-active");
            }
        });
    };

    //get active panel
    const getActivePanel = () => {
        let activePanel;
        DOMstrings.stepFormPanels.forEach(elem => {
            if (elem.classList.contains("js-active")) {
                activePanel = elem;
            }
        });
        return activePanel;
    };

    //open active panel (and close unactive panels)
    const setActivePanel = activePanelNum => {
        //remove active class from all the panels
        removeClasses(DOMstrings.stepFormPanels, "js-active");
        //show active panel
        DOMstrings.stepFormPanels.forEach((elem, index) => {
            if (index === activePanelNum) {
                elem.classList.add("js-active");
                setFormHeight(elem);
            }
        });
    };

    //set form height equal to current panel height
    const formHeight = activePanel => {
        const activePanelHeight = activePanel.offsetHeight;
        DOMstrings.stepsForm.style.height = `${activePanelHeight}px`;
    };

    const setFormHeight = () => {
        const activePanel = getActivePanel();
        formHeight(activePanel);
    };

    //STEPS BAR CLICK FUNCTION
    DOMstrings.stepsBar.addEventListener("click", e => {
        //check if click target is a step button
        const eventTarget = e.target;
        if (
            !eventTarget.classList.contains(
                `${DOMstrings.stepsBtnClass}`
            )
        ) {
            return;
        }
        //get active button step number
        const activeStep = getActiveStep(eventTarget);
        //set all steps before clicked (and clicked too) to active
        setActiveStep(activeStep);
        //open active panel
        setActivePanel(activeStep);
    });

    //PREV/NEXT BTNS CLICK
    DOMstrings.stepsForm.addEventListener("click", e => {
        const eventTarget = e.target;
        //check if we clicked on `PREV` or NEXT` buttons
        if (
            !(
                eventTarget.classList.contains(
                    `${DOMstrings.stepPrevBtnClass}`
                ) ||
                eventTarget.classList.contains(
                    `${DOMstrings.stepNextBtnClass}`
                )
            )
        ) {
            return;
        }

        //find active panel
        const activePanel = findParent(
            eventTarget,
            `${DOMstrings.stepFormPanelClass}`
        );
        let activePanelNum = Array.from(
            DOMstrings.stepFormPanels
        ).indexOf(activePanel);
        //set active step and active panel onclick
        if (
            eventTarget.classList.contains(
                `${DOMstrings.stepPrevBtnClass}`
            )
        ) {
            activePanelNum--;
        } else {
            activePanelNum++;
        }
        setActiveStep(activePanelNum);
        setActivePanel(activePanelNum);

        setTimeout(() => {
            var body = $(".dashboard-content-container");
            body.stop().animate(
                { scrollTop: 0 },
                500,
                "swing",
                function() {}
            );
        }, 100);
    });

    setTimeout(() => {
        setFormHeight();
    }, 500);
    //SETTING PROPER FORM HEIGHT ONLOAD
    window.addEventListener("load", setFormHeight, false);

    //SETTING PROPER FORM HEIGHT ONRESIZE
    window.addEventListener("resize", setFormHeight, false);

    //changing animation via animation select !!!YOU DON'T NEED THIS CODE (if you want to change animation type, just change form panels data-attr)

    const setAnimationType = newType => {
        DOMstrings.stepFormPanels.forEach(elem => {
            elem.dataset.animation = newType;
        });
    };

    //selector onchange - changing animation
    const animationSelect = document.querySelector(
        ".pick-animation__select"
    );
    if (animationSelect != null) {
        animationSelect.addEventListener("change", () => {
            const newAnimationType = animationSelect.value;

            setAnimationType(newAnimationType);
        });
    }
},

By clicking on “Next” button next step is opened, but I need to validate inputs before moving to next step. Please any hints how can I make validation here ? Also is it some library? I searched in net but drowned…

Thanks!

Answer

Each wizard view send wizard position in ajax.In backend based on wizard position validate fields .since you know which and all field exist in each wizard view.

For example consider you have 3 wizard steps.

Step 1 has 3 input fields

Step 2 has 2 input fields

Step 3 has 1 input fields

Suppose if you send current step is 1 then you can only validate those fields.

$validations=[
'step1'=>[
  //field validation array
],
'step3'=>[
  //field validation array
],
'step3'=>[
  //field validation array
],
]

then based on request wizard step you can easily fetch validation rules

Validation::make($validations[$request->step]);

Or you can make all fields validate only if exists in the request