Laravel10+Livewire3表单提交失败问题求助
问题
使用Laravel 10 + Livewire 3开发时,表单提交失败:点击提交按钮后URL变为http://127.0.0.1:8000/admin/jobTrackingByWorker/1_token=Zs6bzTAhWvQOoKU57IQI6GgN3iZ3gMoe5AANb6XE,Livewire控制器的saveAttendanceStatus方法未执行(该方法内有dd('saveAttendanceStatus')但无输出),尝试wire:submit.prevent也无效。
Blade模板tbody代码
@foreach ($daysInMonth as $day) @if ($day['status'] == 0) <tr> <form wire:submit="saveAttendanceStatus"> @csrf <td class="text-black">{{ $day['day'] }}</td> <td> <select wire:model="attendanceStatus"> <option value="">Seçiniz</option> <option value="1">Geldi</option> <option value="2">Yıllık İzin</option> <option value="3">İzinli</option> <option value="4">Hastalık (Raporlu)</option> <option value="5">Hastalık (Raporsuz)</option> <option value="6">Ücretli İzin</option> <option value="7">Yakın Vefatı</option> <option value="8">Evlilik</option> <option value="9">Doğum</option> <option value="10">Askerlik</option> <option value="11">Haber Vermeden Gelmedi</option> <option value="12">Diğer</option> </select> </td> <td> <button type="submit" class="btn btn-primary">Kaydet</button> </td> </form> </tr> @elseif ($day['status'] == 1) <tr> <form wire:submit="updateAttendanceStatus"> @csrf <td class="text-black">{{ $day['day'] }}</td> <td> <select class="form-select" wire:model="attendanceStatus.{{ $day['day'] }}"> <option value="">Seçiniz</option> <option value="1" @if ($day['reason'] == 1) selected @endif>Geldi</option> <option value="2" @if ($day['reason'] == 2) selected @endif>Yıllık İzin</option> <option value="3" @if ($day['reason'] == 3) selected @endif>İzinli</option> <option value="4" @if ($day['reason'] == 4) selected @endif>Hastalık (Raporlu)</option> <option value="5" @if ($day['reason'] == 5) selected @endif>Hastalık (Raporsuz)</option> <option value="6" @if ($day['reason'] == 6) selected @endif>Ücretli İzin</option> <option value="7" @if ($day['reason'] == 7) selected @endif>Yakın Vefatı</option> <option value="8" @if ($day['reason'] == 8) selected @endif>Evlilik</option> <option value="9" @if ($day['reason'] == 9) selected @endif>Doğum</option> <option value="10" @if ($day['reason'] == 10) selected @endif>Askerlik</option> <option value="11" @if ($day['reason'] == 11) selected @endif>Haber Vermeden Gelmedi</option> <option value="12" @if ($day['reason'] == 12) selected @endif>Diğer</option> </select> </td> <td> <button type="submit" class="btn btn-secondary">Güncelle</button> </td> </form> </tr> @else <tr> <td class="text-danger">HATA</td> <td class="text-danger">HATA</td> <td class="text-danger">HATA</td> </tr> @endif @endforeach
Livewire控制器代码
<?php namespace App\Livewire\Admin; use App\Models\JobTracking; use Carbon\Carbon; use Livewire\Component; class JobTrackingByWorker extends Component { public $worker, $attendanceStatus; public function rules() { return [ 'worker' => ['required', 'numeric'], 'attendanceStatus' => ['required', 'numeric'], ]; } public function messages() { return [ 'worker.required' => 'Çalışan seçmelisiniz.', 'worker.numeric' => 'Çalışan seçmelisiniz.', 'attendanceStatus.required' => 'Durum seçmelisiniz.', 'attendanceStatus.numeric' => 'Durum seçmelisiniz.', ]; } public function render() { // Set start date of the month $startOfMonth = Carbon::now()->startOfMonth(); // Take end date of the month $endOfMonth = Carbon::now()->endOfMonth(); // Create an empty array to store the days of the month $daysInMonth = []; // Add days to the array, if the worker has a record for that day, add 1, if not, add 0 $currentDate = $startOfMonth->copy(); while ($currentDate->lte($endOfMonth)) { // Do the worker have a record for that day? $workerCalendar = JobTracking::where('day', $currentDate->toDateString())->where('worker_id', $this->worker)->first(); // If the worker has a record for that day, set status to 1, if not, set status to 0 $status = $workerCalendar ? 1 : 0; $daysInMonth[] = [ 'day' => $currentDate->toDateString(), 'status' => $status, 'reason' => $workerCalendar ? $workerCalendar->description->value : null, ]; $currentDate->addDay(); } return view('livewire.admin.job-tracking-by-worker', compact('daysInMonth')); } public function saveAttendanceStatus() { dd('saveAttendanceStatus'); } }
解决方案
1. 修复无效HTML结构
HTML规范中<tr>标签内只能直接包含<td>或<th>,不能嵌套<form>。这种无效结构会导致Livewire无法正确劫持表单提交,触发传统POST请求(URL出现_token就是明证)。
修改方式:去掉表单标签,改用wire:click直接调用Livewire方法,传递日期参数:
@foreach ($daysInMonth as $day) @if ($day['status'] == 0) <tr> <td class="text-black">{{ $day['day'] }}</td> <td> <select wire:model="attendanceStatus.{{ $day['day'] }}"> <option value="">Seçiniz</option> <option value="1">Geldi</option> <option value="2">Yıllık İzin</option> <option value="3">İzinli</option> <option value="4">Hastalık (Raporlu)</option> <option value="5">Hastalık (Raporsuz)</option> <option value="6">Ücretli İzin</option> <option value="7">Yakın Vefatı</option> <option value="8">Evlilik</option> <option value="9">Doğum</option> <option value="10">Askerlik</option> <option value="11">Haber Vermeden Gelmedi</option> <option value="12">Diğer</option> </select> </td> <td> <button type="button" wire:click="saveAttendanceStatus('{{ $day['day'] }}')" class="btn btn-primary">Kaydet</button> </td> </tr> @elseif ($day['status'] == 1) <tr> <td class="text-black">{{ $day['day'] }}</td> <td> <select class="form-select" wire:model="attendanceStatus.{{ $day['day'] }}"> <option value="">Seçiniz</option> <option value="1" @if ($day['reason'] == 1) selected @endif>Geldi</option> <option value="2" @if ($day['reason'] == 2) selected @endif>Yıllık İzin</option> <option value="3" @if ($day['reason'] == 3) selected @endif>İzinli</option> <option value="4" @if ($day['reason'] == 4) selected @endif>Hastalık (Raporlu)</option> <option value="5" @if ($day['reason'] == 5) selected @endif>Hastalık (Raporsuz)</option> <option value="6" @if ($day['reason'] == 6) selected @endif>Ücretli İzin</option> <option value="7" @if ($day['reason'] == 7) selected @endif>Yakın Vefatı</option> <option value="8" @if ($day['reason'] == 8) selected @endif>Evlilik</option> <option value="9" @if ($day['reason'] == 9) selected @endif>Doğum</option> <option value="10" @if ($day['reason'] == 10) selected @endif>Askerlik</option> <option value="11" @if ($day['reason'] == 11) selected @endif>Haber Vermeden Gelmedi</option> <option value="12" @if ($day['reason'] == 12) selected @endif>Diğer</option> </select> </td> <td> <button type="button" wire:click="updateAttendanceStatus('{{ $day['day'] }}')" class="btn btn-secondary">Güncelle</button> </td> </tr> @else <tr> <td class="text-danger">HATA</td> <td class="text-danger">HATA</td> <td class="text-danger">HATA</td> </tr> @endif @endforeach
2. 调整Livewire属性与方法
- 把
$attendanceStatus改为数组,支持多日期的状态绑定 - 修改
saveAttendanceStatus方法,接收日期参数并验证对应字段 - 移除无用的
@csrf(Livewire自动处理CSRF防护)
<?php namespace App\Livewire\Admin; use App\Models\JobTracking; use Carbon\Carbon; use Livewire\Component; class JobTrackingByWorker extends Component { public $worker; public $attendanceStatus = []; // 改为数组 public function rules() { return [ 'worker' => ['required', 'numeric'], ]; } public function messages() { return [ 'worker.required' => 'Çalışan seçmelisiniz.', 'worker.numeric' => 'Çalışan seçmelisiniz.', "attendanceStatus.*.required" => 'Durum seçmelisiniz.', "attendanceStatus.*.numeric" => 'Durum seçmelisiniz.', ]; } public function render() { $startOfMonth = Carbon::now()->startOfMonth(); $endOfMonth = Carbon::now()->endOfMonth(); $daysInMonth = []; $currentDate = $startOfMonth->copy(); while ($currentDate->lte($endOfMonth)) { $workerCalendar = JobTracking::where('day', $currentDate->toDateString())->where('worker_id', $this->worker)->first(); $status = $workerCalendar ? 1 : 0; $daysInMonth[] = [ 'day' => $currentDate->toDateString(), 'status' => $status, 'reason' => $workerCalendar ? $workerCalendar->description->value : null, ]; // 初始化已存在的状态值 if ($status == 1) { $this->attendanceStatus[$currentDate->toDateString()] = $workerCalendar->description->value; } $currentDate->addDay(); } return view('livewire.admin.job-tracking-by-worker', compact('daysInMonth')); } public function saveAttendanceStatus($day) { // 验证当前日期的状态字段 $this->validate([ "attendanceStatus.$day" => ['required', 'numeric'], ]); // 执行保存逻辑 JobTracking::create([ 'day' => $day, 'worker_id' => $this->worker, 'description' => $this->attendanceStatus[$day], ]); // 重置该字段 unset($this->attendanceStatus[$day]); } public function updateAttendanceStatus($day) { $this->validate([ "attendanceStatus.$day" => ['required', 'numeric'], ]); JobTracking::where('day', $day)->where('worker_id', $this->worker) ->update(['description' => $this->attendanceStatus[$day]]); } }
3. 关键说明
- 无效HTML结构是导致表单提交失败的核心原因,Livewire依赖正确的DOM结构来绑定事件
- 多表单共享单个
attendanceStatus属性会导致数据冲突,改为数组绑定每个日期的状态更合理 - Livewire不需要手动添加
@csrf,框架会自动处理AJAX请求的CSRF验证
内容的提问来源于stack exchange,提问作者Onur
相关产品推荐
相关产品推荐

