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

Bootstrap 5 AJAX模态框中JQuery函数无法获取新值

Bootstrap 5模态框表单验证无法获取字段新值问题

问题场景

在Bootstrap 5模态框中嵌入动态加载的表单,字段初始值通过AJAX填充。用户修改字段值后提交,提交流程正常,但提交前的验证逻辑始终只能读取字段的原始初始值,无法获取用户修改后的新值。

相关代码

模态框打开代码

function viewModal(url,size='lg',fields='') {
    event.preventDefault();

    $.ajax({
        url: url,
        type: 'get',
        success: function(response){ 
            $('.modal-content').html(response);
            $('#genericModal' + size.toUpperCase()).modal('show'); 
        }
    });
}

模态框内容(Blade模板)

<!-- Modal Header -->
<div class="modal-header bg-success text-white">
    <h4 class="modal-title">@if(isset($address)){{'编辑'}}@else{{'添加'}}@endif地址</h4>
    <button type="button" class="btn-close" data-bs-dismiss="modal"></button>
</div>
<form id="formAddress" action="/v3/modals/address" class="needs-validation" method="post">
    @csrf
    @if(isset($address))@method('PATCH')@endif
    @if(isset($address))<input type="hidden" id="id" name="id" value="{{$address->id}}">@endif
    <input type="hidden" id="urlID" name="urlID" value="{{$applicant->urlID}}">
    <!-- Modal body -->
    <div class="modal-body">
        <div class="row">
            <div class="col-lg-6 mb-3">
                <label for="streetLine1" class="form-label"><strong>街道地址1 *</strong></label>
                <input type="text" class="form-control" onchange="quickCheckField('streetLine1')" id="streetLine1" name="streetLine1" placeholder="地址第一行" value="@if(isset($address)){{$address->streetLine1}}@endif" required>
            </div>
            <div class="col-lg-6 mb-3">
                <label for="streetLine2" class="form-label"><strong>街道地址2</strong></label>
                <input type="text" class="form-control" onchange="quickCheckField('streetLine2')" id="streetLine2" name="streetLine2" placeholder="地址第二行" value="@if(isset($address)){{$address->streetLine2}}@endif">
            </div>
        </div>
        <div class="row">
            <div class="col-lg-6 mb-3">
                <label for="town" class="form-label"><strong>城镇/城市</strong></label>
                <input type="text" class="form-control" onchange="quickCheckField('town')" id="town" name="town" placeholder="城镇或城市名称" value="@if(isset($address)){{$address->town}}@endif" required>
            </div>
            <div class="col-lg-6 mb-3">
                <label for="postcode" class="form-label"><strong>邮政编码</strong></label>
                <input type="text" class="form-control" onchange="quickCheckField('postcode')" id="postcode" name="postcode" placeholder="邮政编码" value="@if(isset($address)){{$address->postcode}}@endif" required>
            </div>
        </div>
        <div class="row">
            <div class="col-lg-6 mb-3">
                <label for="countryID" class="form-label"><strong>国家</strong></label>
                <select class="form-control"  onchange="quickCheckField('countryID')" id="countryID" name="countryID" required>
                    <option value="">请选择...</option>
                    <option value="1">英国</option>
                    <option value="105">爱尔兰</option>
                    <option disabled>----------</option>
                    @foreach ($countries as $field)<option value="{{ $field->id }}"@if(isset($address))@if($field->id==$address->countryID){{'selected'}}@endif @endif>{{$field->countryName}}</option>@endforeach
                </select>
            </div>
        </div>
        <div class="row">
            <div class="col-lg-6 mb-3">
                <label for="dateFromM" class="form-label"><strong>入住日期 *</strong></label>
                <div class="input-group">
                    <select class="reqField form-control" onchange="quickCheckField('dateFromM')" id="dateFromM" name="dateFromM" required>
                        <option value="">月份</option>
                        @for($i=1;$i<=12;$i++)<option value="{{str_pad($i,2,'0',STR_PAD_LEFT)}}"@if(isset($address))@if(str_pad($i,2,'0',STR_PAD_LEFT)==substr($address->dateFrom,5,2)){{'selected'}}@endif @endif>{{date_format(date_create("01-" . $i . "-2000"), "M")}} ({{str_pad($i,2,'0',STR_PAD_LEFT)}})</option>@endfor
                    </select>
                    <select class="reqField form-control" onchange="quickCheckField('dateFromY')" id="dateFromY" name="dateFromY" required>
                        <option value="">年份</option>
                        @for($i=(date('Y'));$i>=(date('Y')-110);$i--)<option value="{{$i}}"@if(isset($address))@if($i==substr($address->dateFrom,0,4)){{'selected'}}@endif @endif>{{$i}}</option>@endfor
                    </select>
                </div>
            </div>
            <div class="col-lg-6 mb-3">
                <label for="dateTillM" class="form-label"><strong>搬离日期 *</strong></label>
                <div class="input-group">
                    <select class="reqField form-control" onchange="quickCheckField('dateTillM')" id="dateTillM" name="dateTillM" required>
                        <option value="">月份</option>
                        @for($i=1;$i<=12;$i++)<option value="{{str_pad($i,2,'0',STR_PAD_LEFT)}}"@if(isset($address))@if(str_pad($i,2,'0',STR_PAD_LEFT)==substr($address->dateTill,5,2)){{'selected'}}@endif @endif>{{date_format(date_create("01-" . $i . "-2000"), "M")}} ({{str_pad($i,2,'0',STR_PAD_LEFT)}})</option>@endfor
                    </select>
                    <select class="reqField form-control" onchange="quickCheckField('dateTillY')" id="dateTillY" name="dateTillY" required>
                        <option value="">年份</option>
                        @for($i=(date('Y'));$i>=(date('Y')-110);$i--)<option value="{{$i}}"@if(isset($address))@if($i==substr($address->dateTill,0,4)){{'selected'}}@endif @endif>{{$i}}</option>@endfor
                    </select>
                </div>
            </div>
        </div>
        <div id="formErrorMessage" class="text-danger text-center"></div>
    </div>
    <!-- Modal footer -->
    <div class="modal-footer">
        <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">取消</button>
        @if(isset($address))<button class="btn btn-outline-danger" id="btnDeleteName" onclick="confirmDelete()">删除地址</button>@endif
        <button type="submit" class="btn btn-success" id="btnSaveAddress">保存地址</button>
    </div>
</form>

原验证代码

<script>
    $("#btnSaveAddress").on("click", function(e) {
        e.preventDefault();

        $("#formErrorMessage").text("");

        $reqFields = [ "streetLine1", "town", "postcode", "countryID", "dateFromM", "dateFromY", "dateTillM", "dateTillY" ];

        $passedValidation = true;

        $.each($reqFields, function( i, fieldID ) {
            if ($("#" + fieldID).val() == "") {
                $passedValidation = false;
                $("#" + fieldID).removeClass("is-valid");
                $("#" + fieldID).addClass("is-invalid");
            } else {
                $("#" + fieldID).removeClass("is-invalid");
                $("#" + fieldID).addClass("is-valid");
            }
        });

        if ($("#dateFromY").val() + $("#dateFromM").val() >= $("#dateTillY").val() + $("#dateTillM").val()) {
            $passedValidation = false;
            $("#dateTillM").removeClass("is-valid");
            $("#dateTillM").addClass("is-invalid");
            $("#dateTillY").removeClass("is-valid");
            $("#dateTillY").addClass("is-invalid");
            $("#formErrorMessage").text("The Date Till must be after the Date From");
        }

        if ($passedValidation == true) {
            $("#formAddress").trigger("submit");
        }
    });
</script>

问题原因

核心问题是事件绑定时机错误:原验证代码直接将点击事件绑定到#btnSaveAddress元素,但该按钮是通过AJAX动态加载到模态框中的,页面初始化时DOM中不存在该元素,导致绑定的事件实际上并未生效;当多次打开模态框时,旧的DOM元素和事件监听可能残留,导致读取的是缓存的原始值。

解决方案

1. 使用事件委托绑定验证事件

将事件绑定到页面初始化时就存在的父元素(如body),确保动态生成的按钮能触发验证逻辑:

// 事件委托绑定,兼容动态加载的元素
$("body").on("click", "#btnSaveAddress", function(e) {
    e.preventDefault();

    $("#formErrorMessage").text("");

    // 使用const/let替代全局变量,避免污染
    const reqFields = [ "streetLine1", "town", "postcode", "countryID", "dateFromM", "dateFromY", "dateTillM", "dateTillY" ];
    let passedValidation = true;

    $.each(reqFields, function( i, fieldID ) {
        // 实时读取字段当前值,去除空白字符
        const fieldValue = $("#" + fieldID).val().trim();
        if (fieldValue === "") {
            passedValidation = false;
            $("#" + fieldID).removeClass("is-valid").addClass("is-invalid");
        } else {
            $("#" + fieldID).removeClass("is-invalid").addClass("is-valid");
        }
    });

    // 实时读取日期字段值,避免缓存
    const dateFrom = $("#dateFromY").val() + $("#dateFromM").val();
    const dateTill = $("#dateTillY").val() + $("#dateTillM").val();
    if (dateFrom >= dateTill) {
        passedValidation = false;
        // 批量操作DOM,简化代码
        $("#dateTillM, #dateTillY").removeClass("is-valid").addClass("is-invalid");
        $("#formErrorMessage").text("结束日期必须晚于开始日期");
    }

    if (passedValidation) {
        $("#formAddress").submit();
    }
});

2. 优化模态框加载逻辑(可选)

在AJAX成功回调中先清空模态内容,避免残留旧DOM和事件:

function viewModal(url,size='lg',fields='') {
    event.preventDefault();

    $.ajax({
        url: url,
        type: 'get',
        success: function(response){ 
            // 先清空再填充新内容,避免残留
            $('.modal-content').empty().html(response);
            $('#genericModal' + size.toUpperCase()).modal('show'); 
            // 可选:重置表单状态
            const form = $('#formAddress')[0];
            if (form) form.reset();
        }
    });
}

说明

  • 事件委托:利用事件冒泡机制,将事件绑定到静态父元素,确保动态生成的按钮能触发验证逻辑。
  • 实时读取值:每次验证时直接从DOM获取当前值,添加trim()处理空白输入,提升验证准确性。
  • 代码优化:使用const/let替代全局变量,批量操作DOM简化代码结构。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.15 16:44:56