jQuery表单提交触发模态框执行不同操作遇无限循环求优雅方案
问题描述
我有一个待提交的表单,提交时需要阻止默认行为,通过AJAX请求检查是否存在已有记录,逻辑如下:
- 若不存在记录,则正常提交表单;
- 若存在记录,则弹出模态框询问用户是否关闭该已有记录:
- 用户确认时,为
id字段设置对应值; - 用户拒绝时,继续正常提交表单。
- 用户确认时,为
当前实现陷入了无限循环,虽然可以用全局布尔变量判断是否直接提交,但肯定有更优雅的方式,特此求助。
现有代码
JavaScript(含Laravel模板代码)
<script type="text/javascript"> $(document).ready(function() { $(document).on('click', '#button-close-previous-status', function() { $('#form-create-status').submit(); }); $(document).on('click', '#button-ignore-previous-status', function() { $('#open_status_id').val(''); $('#form-create-status').submit(); }); $('#modal-title-close-previous-status').on('hidden.bs.modal', function () { $('#close-status-end-date').empty(); $('#close-status-status').empty(); $('#close-status-start-date').empty(); $('#open_status_id').val(''); }); $('#form-create-status').submit(function(e) { // this code prevents form from actually being submitted e.preventDefault(); e.returnValue = false; if (!$('#status_start').val()) { swtAlert('error', '{{__('Missing Information')}}', '{{__('Please enter the status start date')}}'); } else { var $form = $(this); $.ajax({ url: "{{route('baadmin.students.bursaries.statuses.get_open_student_bursary_statuses',['student'=>$student->id,'bursary'=>$student_bursary->id])}}", type: "post", dataType: 'json', context: $form, data: { status_start: $('#status_start').val() }, headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') }, success: function (data) { if (data.id>0) { var parts =$('#status_start').val().split('-'); var end_date = new Date(parts[0], parts[1] - 1, parts[2]); end_date.setDate(end_date.getDate() - 1); end_date = end_date.toLocaleDateString('en-CA', {year: 'numeric', month: '2-digit', day: '2-digit'}); $('#close-status-end-date').text(end_date); $('#close-status-status').text(data.text); $('#close-status-start-date').text(data.status_start); $('#open_status_id').val(data.id); $('#modal-close-previous-status').modal('show'); } else { swtAlert('error','Communications Error',"Couldn't fetch existing statuses. Cant request auto-close."); // make sure that you are no longer handling the submit event; clear handler this.off('submit'); // actually submit the form this.submit(); } }, }); } }); }); </script>
模态框HTML(含Laravel模板代码)
<div class="modal fade" id="modal-close-previous-status" tabindex="-1" role="dialog" aria-labelledby="modal-title-close-previous-status" aria-hidden="true" style="display: none;"> <div class="modal-dialog modal-dialog-centered" role="document"> <div class="modal-content"> <div class="modal-header"> <h5 class="modal-title" id="modal-title-close-previous-status">{{__('Close Previous Status')}}</h5> <button type="button" class="close" data-dismiss="modal" aria-label="Close"> <span aria-hidden="true">×</span> </button> </div> <div class="modal-body"> <p>We found a previously open status. Would you like to close that status with a status end date of <span id="close-status-end-date"></span>.</p> <p> <strong>Found Status:</strong><br> Status: <span id="close-status-status"></span><br/> Status Start: <span id="close-status-start-date"></span> </p> </div> <div class="modal-footer"> {{ Form::button(__('Dont Change Anything'), ['type' => 'button', 'class' => 'btn btn-secondary', 'data-dismiss'=>'modal','id'=>'button-ignore-previous-status']) }} {{ Form::button(__('Close Previous Status'), ['type' => 'button', 'class' => 'btn btn-success','id'=>'button-close-previous-status']) }} </div> </div> </div> </div>
解决方案
问题根源在于:模态框按钮触发的submit()会再次执行绑定的事件处理函数,导致重复AJAX检查,陷入循环。以下是两种优雅的解决方式:
方式一:调用原生表单提交方法
直接调用表单的原生submit()方法,而非jQuery封装的submit(),这样不会触发绑定的jQuery事件处理函数,直接提交表单:
修改模态框按钮的点击事件:
$(document).on('click', '#button-close-previous-status', function() { // 调用原生submit,跳过jQuery事件监听 document.getElementById('form-create-status').submit(); }); $(document).on('click', '#button-ignore-previous-status', function() { $('#open_status_id').val(''); // 调用原生submit,跳过jQuery事件监听 document.getElementById('form-create-status').submit(); });
同时,把原有AJAX成功后无记录的提交逻辑也改为原生submit:
success: function (data) { if (data.id>0) { // 原有模态框渲染逻辑保持不变 } else { swtAlert('error','Communications Error',"Couldn't fetch existing statuses. Cant request auto-close."); // 调用原生submit提交表单 this[0].submit(); } }
方式二:用自定义标记区分提交类型
给表单加一个自定义属性,标记是否需要跳过AJAX检查:
修改JavaScript部分:
$(document).ready(function() { $(document).on('click', '#button-close-previous-status', function() { $('#form-create-status').attr('data-skip-check', 'true'); $('#form-create-status').submit(); }); $(document).on('click', '#button-ignore-previous-status', function() { $('#open_status_id').val(''); $('#form-create-status').attr('data-skip-check', 'true'); $('#form-create-status').submit(); }); // 模态框隐藏时移除标记,恢复正常检查逻辑 $('#modal-title-close-previous-status').on('hidden.bs.modal', function () { $('#close-status-end-date').empty(); $('#close-status-status').empty(); $('#close-status-start-date').empty(); $('#open_status_id').val(''); $('#form-create-status').removeAttr('data-skip-check'); }); $('#form-create-status').submit(function(e) { // 检查标记,若存在则跳过检查直接提交 if ($(this).attr('data-skip-check') === 'true') { $(this).removeAttr('data-skip-check'); return; } // 原有阻止默认行为、AJAX检查逻辑保持不变 e.preventDefault(); e.returnValue = false; if (!$('#status_start').val()) { swtAlert('error', '{{__('Missing Information')}}', '{{__('Please enter the status start date')}}'); } else { var $form = $(this); $.ajax({ url: "{{route('baadmin.students.bursaries.statuses.get_open_student_bursary_statuses',['student'=>$student->id,'bursary'=>$student_bursary->id])}}", type: "post", dataType: 'json', context: $form, data: { status_start: $('#status_start').val() }, headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') }, success: function (data) { if (data.id>0) { var parts =$('#status_start').val().split('-'); var end_date = new Date(parts[0], parts[1] - 1, parts[2]); end_date.setDate(end_date.getDate() - 1); end_date = end_date.toLocaleDateString('en-CA', {year: 'numeric', month: '2-digit', day: '2-digit'}); $('#close-status-end-date').text(end_date); $('#close-status-status').text(data.text); $('#close-status-start-date').text(data.status_start); $('#open_status_id').val(data.id); $('#modal-close-previous-status').modal('show'); } else { swtAlert('error','Communications Error',"Couldn't fetch existing statuses. Cant request auto-close."); this[0].submit(); } }, }); } }); });
内容的提问来源于stack exchange,提问作者SupaMonkey
相关产品推荐
相关产品推荐

