You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel Blade多步骤表单:仅勾选选项后显示下一步按钮

问题:Laravel Blade多步骤表单“下一步”按钮需勾选单选框才显示的功能失效

我基于多步骤表单方案在Laravel Blade视图中构建了考试表单,需求是只有勾选当前页面的单选框选项后,才显示“下一步”按钮,但目前该功能无法正常工作。以下是代码分析及修复方案:

原代码问题分析

  1. validateForm函数中的核心验证逻辑被注释,无法判断单选框是否选中
  2. 当前tab内存在一个hidden类型的input(值为空),会干扰验证判断
  3. “下一步”按钮默认显示,未实现初始隐藏
  4. 缺少单选框选择事件监听,无法实时更新按钮状态

修复方案

1. 修改Blade表单代码(添加单选框监听类)

给所有单选框添加统一类名question-radio,方便绑定事件:

<form method="POST" action="{{ route('stagiaire.theorique.test.store_seul',['id'=>$eval->id]) }}" id="questionform" name="examForm">
    @csrf

    <div style="text-align:center;margin-top:10px;">
        <span class="step"></span>
        <span class="step"></span>
        <span class="step"></span>
        <span class="step"></span>
    </div>

    @foreach($questioncat as $key => $category)
                @foreach($category->getQuestion as $question)
                    <fieldset class="theorique-body" id="categorie_{{ $key }}">

                        <div class="header-question" id="q{{ $question->id}}">
                            <h2 class="nomcat">{{ $category->nom }}</h2>
                            <h3 class="question">{{ $question->question_text }}</h3>
                        </div>
                        <div class="body-question">
                            <div class="image">
                                    <img src="{{ asset('storage/' . $question->image) }}" alt="">
                            </div>
                            <div class="reponsebouton">
                            <input type="hidden" name="questions[{{ $question->id }}]" value="">
                                <p>Merci de choisir votre réponse</p>
                                @foreach($question->reponse as $option)

                                <div class="button-check">
                                    <input class="form-check-input question-radio" type="radio" name="questions[{{ $question->id }}]" id="option-{{ $option->id }}" value="{{ $option->id }}"@if(old("questions.$question->id") == $option->id) checked @endif>
                                        <label class="form-check-label" for="option-{{ $option->id }}">
                                            {{ $option->option_text }}
                                        </label>
                                </div>
                                @endforeach

                            </div>
                        </div>
                    </fieldset>


                        @if($errors->has("questions.$question->id"))
                        <p class="font-bold">Attention :</p>
                                <span style="margin-top: .25rem; font-size: 80%; color: #e3342f;" role="alert">
                                    <strong>{{ $errors->first("questions.$question->id") }}</strong>
                                </span>
                        @endif

                @endforeach
    @endforeach
    <div style="overflow:auto;" id="butform">
        <div style="float:right;">
            <button type="button" id="prevBtn" onclick="nextPrev(-1)">Previous</button>
            <button class="text-white bg-gradient-to-br from-purple-600 to-blue-500 hover:bg-gradient-to-bl focus:ring-4 focus:outline-none focus:ring-blue-300 dark:focus:ring-blue-800 rounded-lg text-m px-5 py-4 font-bold uppercase text-center mr-2 mb-2" type="button" id="nextBtn" onclick="nextPrev(1)" style="display:none;">Suivant</button>
        </div>
    </div>
</form>

2. 修改JavaScript代码(完善验证与监听逻辑)

var currentTab = 0; // 当前选中的标签页索引
showTab(currentTab); // 显示初始标签页

// 给所有单选框绑定选择事件监听
document.querySelectorAll('.question-radio').forEach(radio => {
    radio.addEventListener('change', updateNextButtonStatus);
});

function showTab(n) {
    const tabs = document.getElementsByClassName("theorique-body");
    // 隐藏所有标签页
    for(let i = 0; i < tabs.length; i++){
        tabs[i].style.display = "none";
    }
    // 显示当前标签页
    tabs[n].style.display = "block";
    
    // 处理上一步按钮显示逻辑
    document.getElementById("prevBtn").style.display = n === 0 ? "none" : "inline-block";
    
    // 处理下一步按钮文本
    document.getElementById("nextBtn").innerHTML = n === tabs.length - 1 ? "Terminer le test" : "Suivant";
    
    // 更新下一步按钮状态
    updateNextButtonStatus();
    // 更新步骤指示器
    fixStepIndicator(n);
}

function nextPrev(n) {
    const tabs = document.getElementsByClassName("theorique-body");
    // 下一步时验证当前表单
    if (n === 1 && !validateForm()) return false;
    
    tabs[currentTab].style.display = "none";
    currentTab += n;
    
    // 到达表单末尾则提交
    if (currentTab >= tabs.length) {
        document.getElementById("questionform").submit();
        return false;
    }
    showTab(currentTab);
}

function validateForm() {
    const currentTabEl = document.getElementsByClassName("theorique-body")[currentTab];
    // 仅获取当前tab内的单选框
    const radios = currentTabEl.querySelectorAll('input[type="radio"]');
    let valid = false;
    
    // 检查是否有单选框被选中
    for(let i = 0; i < radios.length; i++){
        if(radios[i].checked){
            valid = true;
            break;
        }
    }
    
    // 标记步骤为已完成
    if (valid) {
        document.getElementsByClassName("step")[currentTab].className += " finish";
    }
    return valid;
}

// 更新下一步按钮显示状态
function updateNextButtonStatus(){
    const nextBtn = document.getElementById("nextBtn");
    nextBtn.style.display = validateForm() ? "inline-block" : "none";
}

function fixStepIndicator(n) {
    const steps = document.getElementsByClassName("step");
    for (let i = 0; i < steps.length; i++) {
        steps[i].className = steps[i].className.replace(" active", "");
    }
    steps[n].className += " active";
}

关键修改说明

  • 给单选框添加question-radio类,统一监听选择事件
  • 初始隐藏“下一步”按钮,通过updateNextButtonStatus函数实时控制显示/隐藏
  • 修复validateForm函数,仅检查当前tab内的单选框是否被选中,排除hidden input干扰
  • 优化showTab函数,先隐藏所有标签页再显示当前页,避免显示混乱
  • 提取updateNextButtonStatus函数,专门处理按钮状态更新

内容的提问来源于stack exchange,提问作者Chrisdev

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 18:31:09