Livewire 3表单提交后触发验证码模态窗的问题及报错解决
表单提交后无法正常弹出验证码模态窗(含Bootstrap报错)
我在实现表单提交后显示模态窗时遇到问题:预订记录写入数据库后,需要立即弹出让用户输入验证码的模态窗,但功能无法实现。更新代码后出现如下报错:
Uncaught TypeError: Cannot read properties of undefined (reading 'backdrop') at On._initializeBackDrop (modal.js:158:39) at new On (modal.js:69:27) at On.getOrCreateInstance (base-component.js:65:41) at HTMLButtonElement.<anonymous> (modal.js:363:22) at HTMLDocument.n (event-handler.js:118:19)
相关代码
Booking组件代码
<?php namespace App\Livewire; use Livewire\Component; use App\Models\Reservation; use App\Mail\ReservationMail; use Illuminate\Support\Facades\Mail; use App\Models\AvailableBusinessHour; use App\Events\ShowVerificationModal; // Přidejte tuto řádku pro event class Booking extends Component { public $full_name; public $email; public $phone_number; public $reservation; public $selectedService; public $available_business_hour_id; public $selectedBusinessHourId; public $verification_code; public $successMessage; public $showVerificationModal = false; public $successMessageVisible; public $successMessageTimeout = 3000; public function render() { $this->available_business_hour_id = AvailableBusinessHour::whereDoesntHave('reservation')->orderBy('day')->orderBy('from')->get(); return view('livewire.booking', [ 'emptyOption' => 'Vyber si čas rezervace', ]); } public function store() { $this->validate([ 'full_name' => 'required|string|max:250', 'email' => 'required|email|max:250', 'phone_number' => 'required|phone:CZ', 'selectedService' => 'required', 'available_business_hour_id' => 'required|unique:reservations', ], [ 'available_business_hour_id.unique' => 'Tento termín byl již obsazen, vyber jiný pokud je nějaký dostupný.', 'available_business_hour_id.required' => 'Výběr času objednání je povinné pole.', 'phone_number.phone' => 'Chybný formát telefonního čísla.', 'selectedService.required' => 'Toto je povinné pole', ]); $selectedBusinessHour = AvailableBusinessHour::find($this->selectedBusinessHourId); $verification_code = rand(100000, 999999); $reservation = Reservation::create([ 'full_name' => $this->full_name, 'email' => $this->email, 'phone_number' => $this->phone_number, 'service' => $this->selectedService, 'available_business_hour_id' => $this->selectedBusinessHourId, 'day' => $selectedBusinessHour['day'], 'from' => $selectedBusinessHour['from'], 'to' => $selectedBusinessHour['to'], 'verification_code' => $verification_code ]); $this->sendReservationConfirmationMail($reservation); $this->successMessage = 'Rezervace proběhla úspěšně.'; $this->successMessageVisible = true; $this->showVerificationModal = true; $this->reset(['full_name', 'email', 'phone_number', 'available_business_hour_id']); } public function sendReservationConfirmationMail($reservation) { Mail::to($reservation->email)->send(new ReservationMail($reservation)); } public function services() { return ["Stříhání vlasů", "Stříhání + úprava vousů", "Barvení vousů", "Junior střih", "Úprava vousů"]; } }
Booking组件对应的Blade视图
<section id="booking"> <div class="container"> @if ($successMessageVisible) <div x-data="{ show: true }" x-init="setTimeout(() => show = false, {{ $successMessageTimeout }})" x-show="show" class="alert alert-success"> {{ $successMessage }} </div> @endif <form wire:submit.prevent="store"> @csrf <div class="col-12 mb-4"> <h1 class="modal-title fs-5 text-center" id="bookingModalLabel">Objednej se</h1> <p class="">Lorem, ipsum dolor sit amet consectetur adipisicing elit. Lorem, ipsum dolor sit amet consectetur adipisicing elit.</p> </div> <div class="form-group col-12"> <input type="text" wire:model="full_name" id="full_name" name="full_name" class="form-control" placeholder="Celé jméno*" required> </div> <div class="form-group col-12"> <input type="email" wire:model="email" id="email" name="email" class="form-control" placeholder="Email*" required> </div> <div class="form-group col-12"> <input type="text" wire:model="phone_number" id="phone_number" name="phone_number" class="form-control" placeholder="Tel. číslo ve formátu +420700700700" required> @error('phone_number') <span class="text-danger">{{ $message }}</span> @enderror </div> <div class="form-group col-12"> <select wire:model="selectedService" class="form-control"> <option value="">Vyberte službu</option> @foreach ($this->services() as $service) <option value="{{ $service }}">{{ $service }}</option> @endforeach </select> @error('selectedService') <span class="text-danger">{{ $message }}</span> @enderror </div> <div class="form-group col-12 mt-3"> <select wire:model="selectedBusinessHourId" class="form-control"> <option value="">{{ $emptyOption }}</option> @foreach ($available_business_hour_id as $time) <option value="{{ $time['id'] }}">{{ $time['formattedDayAndDate'] }} od {{ $time['from'] }} do {{ $time['to'] }}</option> @endforeach </select> @error('available_business_hour_id') <span class="text-danger">{{ $message }}</span> @enderror </div> <div class="form-group col-12 text-center"> <div class="cta-btns"> <button type="submit" class="btn btn-service me-sm-2" data-bs-toggle="modal" data-bs-target="#exampleModal">Odeslat</button> @if ($showVerificationModal) <livewire:verification-modal /> @endif </div> </div> </form> </div> </section>
VerificationModal组件代码
<?php namespace App\Livewire; use Livewire\Component; class VerificationModal extends Component { protected $listeners = ['showVerificationModal']; public function render() { return view('livewire.verification-modal'); } }
VerificationModal组件对应的Blade视图
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true"> <div class="modal-dialog"> <div class="modal-content"> <div class="modal-header"> <h1 class="modal-title fs-5" id="exampleModalLabel">Modal title</h1> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button> </div> <div class="modal-body"> <div class="verification-code-container"> {{-- <input type="text" wire:model="verification_code" id="verification_code" name="verification_code" class="form-control" placeholder="Verifikační kód" required> --}} </div> </div> <div class="modal-footer"> <button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button> <button type="button" class="btn btn-primary">Save changes</button> </div> </div> </div> </div>
解决方案
问题根源
- 报错是因为提交按钮自带Bootstrap模态触发属性,点击时会直接尝试打开模态窗,但此时模态窗组件还未渲染(受
@if($showVerificationModal)条件限制),导致Bootstrap找不到DOM元素抛出错误。 - 表单验证规则中字段名不匹配,
available_business_hour_id对应的数据实际是selectedBusinessHourId,会导致验证失效。 - 模态窗的显示逻辑依赖组件条件渲染,无法实时响应Livewire状态变化。
修复步骤
1. 移除提交按钮的Bootstrap触发属性
修改Booking视图中的提交按钮,去掉data-bs-toggle和data-bs-target:
<button type="submit" class="btn btn-service me-sm-2">Odeslat</button>
2. 调整模态窗渲染位置
把livewire:verification-modal移出条件判断,放在表单外部确保DOM始终存在:
</form> <livewire:verification-modal />
3. 通过Livewire事件控制模态窗显示
修改Booking组件的store方法,用事件触发替代直接赋值:
// 替换$this->showVerificationModal = true; $this->dispatch('show-verification-modal');
更新VerificationModal组件,监听事件并调用Bootstrap API:
namespace App\Livewire; use Livewire\Component; class VerificationModal extends Component { protected $listeners = ['show-verification-modal' => 'openModal']; public function openModal() { $this->dispatch('trigger-modal'); } public function render() { return view('livewire.verification-modal'); } }
修改VerificationModal的Blade视图,用Alpine.js监听事件并打开模态窗:
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true" x-data x-on:trigger-modal.window="new bootstrap.Modal(document.getElementById('exampleModal')).show()" > <!-- 原有模态窗内容不变 --> </div>
4. 修正表单验证字段
把store方法中的验证规则字段名改为selectedBusinessHourId:
$this->validate([ // ...其他规则 'selectedBusinessHourId' => 'required|unique:reservations,available_business_hour_id', ], [ 'selectedBusinessHourId.unique' => 'Tento termín byl již obsazen, vyber jiný pokud je nějaký dostupný.', 'selectedBusinessHourId.required' => 'Výběr času objednání je povinné pole.', // ...其他错误信息 ]);
5. 完善表单重置逻辑
确保所有表单字段都被重置:
$this->reset(['full_name', 'email', 'phone_number', 'selectedService', 'selectedBusinessHourId']);
修复后流程
用户提交表单→验证通过创建预订记录→触发Livewire事件→VerificationModal组件收到事件后调用Bootstrap API打开模态窗→用户输入验证码完成验证。
内容的提问来源于stack exchange,提问作者user22809416
相关产品推荐
相关产品推荐

