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

使用Livewire实现带关联下拉框的动态增删行及问题排查

动态增删行级联下拉框的Livewire组件修复方案

问题说明

使用Livewire构建带动态增删行的关联级联下拉框时,遇到两个问题:

  • 无法获取每行下拉框的独立选中值
  • 选择某一行的品牌后,所有行的设备下拉框内容同步更新为该品牌对应的设备

问题根源

  1. 原代码中$brand、$item为单个变量,而非数组,无法存储多行的独立选中值
  2. $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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 14:15:32