使用Livewire实现带关联下拉框的动态增删行及问题排查
动态增删行级联下拉框的Livewire组件修复方案
问题说明
使用Livewire构建带动态增删行的关联级联下拉框时,遇到两个问题:
- 无法获取每行下拉框的独立选中值
- 选择某一行的品牌后,所有行的设备下拉框内容同步更新为该品牌对应的设备
问题根源
- 原代码中
$brand、$item为单个变量,而非数组,无法存储多行的独立选中值 $items为单个集合,所有行共享同一设备列表,导致联动时全局更新
修改后的代码
1. Livewire组件类:/project/app/Http/Livewire/DeviceSale.php
<?php namespace App\Http\Livewire; use App\Models\Item; use App\Models\Brand; use Livewire\Component; class DeviceSale extends Component { public $brands = []; public $items = []; // 改为数组,存储每行对应的设备列表 public $brand = []; // 改为数组,存储每行选中的品牌ID public $item = []; // 改为数组,存储每行选中的设备ID public $inputs = []; public $i = 1; public function render() { $this->brands = Brand::orderBy('brand_name', 'asc')->get(); // 初始化第一行的设备列表为空 if (!isset($this->items[0])) { $this->items[0] = collect(); } return view('livewire.device-sale'); } public function add($i) { $i = $i + 1; $this->i = $i; array_push($this->inputs, $i); // 初始化新行的品牌、设备值和设备列表 $this->brand[$i] = -1; $this->item[$i] = -1; $this->items[$i] = collect(); } public function remove($key) { unset($this->inputs[$key]); unset($this->brand[$key]); unset($this->item[$key]); unset($this->items[$key]); } // 接收行索引,更新对应行的设备列表 public function updateItem($index) { $brandId = $this->brand[$index] ?? -1; if ($brandId != -1) { $this->items[$index] = Item::where('brand_id', $brandId) ->orderBy('item_name', 'asc')->get(); } else { $this->items[$index] = collect(); } // 清空当前行选中的设备,避免品牌切换后设备不匹配 $this->item[$index] = -1; } }
2. Blade视图文件:/project/resources/views/livewire/device-sale.blade.php
<div class="row"> <div class="col-5"> <label class="form-label mt-0">Select Brand</label> <select id="brand.0" class="form-control" name="brand[]" wire:model="brand.0" wire:change="updateItem(0)"> <option value="-1">Select Brand</option> @foreach ($brands as $brand) <option value="{{ $brand->id }}">{{ $brand->brand_name }}</option> @endforeach </select> @error('brand.0') <div class="text-danger text-sm">{{ $message }}</div> @enderror </div> <div class="col-5"> <label class="form-label mt-0">Device Name</label> <div class="form-group mb-0"> <select id="item.0" class="form-control" name="item[]" wire:model="item.0"> <option value="-1">Select Device</option> @foreach ($items[0] ?? [] as $item) <option value="{{ $item->id }}">{{ $item->item_name }}</option> @endforeach </select> @error('item.0') <div class="text-danger text-sm">{{ $message }}</div> @enderror </div> </div> <div class="col-2"> <button class="btn text-white btn-info btn-sm mt-4" wire:click.prevent="add({{ $i }})">Add</button> </div> @foreach ($inputs as $key => $value) <div class="add-input"> <div class="row"> <div class="col-5"> <label class="form-label mt-0">Select Brand</label> <select id="brand.{{ $value }}" class="form-control" name="brand[]" wire:model="brand.{{ $value }}" wire:change="updateItem({{ $value }})"> <option value="-1">Select Brand</option> @foreach ($brands as $brand) <option value="{{ $brand->id }}">{{ $brand->brand_name }}</option> @endforeach </select> @error("brand.$value") <div class="text-danger text-sm">{{ $message }}</div> @enderror </div> <div class="col-5"> <label class="form-label mt-0">Device Name</label> <div class="form-group mb-0"> <select class="form-control" name="item[]" wire:model="item.{{ $value }}"> <option value="-1">Select Device</option> @foreach ($items[$value] ?? [] as $item) <option value="{{ $item->id }}">{{ $item->item_name }}</option> @endforeach </select> @error("item.$value") <div class="text-danger text-sm">{{ $message }}</div> @enderror </div> </div> <div class="col-2"> <button class="btn btn-danger btn-sm mt-4" wire:click.prevent="remove({{ $key }})">Remove</button> </div> </div> </div> @endforeach </div>
关键修改点
- 将
$brand、$item、$items改为数组,实现每行数据的独立存储 updateItem方法接收行索引参数,仅更新对应行的设备列表- 新增行时初始化对应索引的品牌、设备值和空设备列表
- 视图中
wire:change传递当前行索引,设备下拉框循环对应索引的items数组 - 修复错误信息的变量引用,确保对应行的错误提示正确
内容的提问来源于stack exchange,提问作者Joney Spark
相关产品推荐
相关产品推荐

