如何用Livewire实现嵌套组件向父组件传参并解决房间保存问题?
问题分析与解决方案
问题概述
使用Livewire搭建房屋与房间的增编系统时,房屋信息可正常保存,但房间数据无法同步保存,尝试通过$emitUp传递房间参数至父组件的操作未生效。
核心问题点
- Room视图参数传递错误:使用模板插值
{{ $id }}/{{ $name }}传递参数,仅能渲染初始值,无法获取输入框更新后的动态值。 - 父组件属性缺失:Houses组件未定义
$rooms(存储房间数据)和$house_id(当前操作房屋ID)属性,导致存储逻辑无法执行。 - 房间存储逻辑低效:原代码直接删除所有房间再重建,可优化为仅清理未保留的房间。
修正后的代码实现
1. RoomShow组件(子组件)
// app/Http/Livewire/RoomShow.php namespace App\Http\Livewire; use Livewire\Component; class RoomShow extends Component { public $room; public function mount($room) { $this->room = $room; } public function render() { return view('livewire.rooms.room'); } }
2. Room视图文件
{{-- views/livewire/rooms/room.blade.php --}} <div> <input type="text" wire:model="room.name" placeholder="房间名称" wire:change="$emitUp('roomUpdated', room.id, room.name)"> </div>
3. Houses组件(父组件)
// app/Http/Livewire/Houses.php namespace App\Http\Livewire; use App\Models\House; use App\Models\Room; use Livewire\Component; class Houses extends Component { public $houses, $address1, $town, $house_id; public $isOpen = 0; public $rooms = []; protected $listeners = ['roomUpdated' => 'updateRoom']; public function render() { $this->houses = House::all(); return view('livewire.houses.houses'); } // 打开创建/编辑模态框 public function create() { $this->resetInputFields(); $this->openModal(); } // 加载编辑数据 public function edit($id) { $house = House::findOrFail($id); $this->house_id = $id; $this->address1 = $house->address1; $this->town = $house->town; $this->rooms = $house->rooms->toArray(); $this->openModal(); } public function openModal() { $this->isOpen = true; } public function closeModal() { $this->isOpen = false; } // 重置表单字段 private function resetInputFields() { $this->house_id = null; $this->address1 = ''; $this->town = ''; $this->rooms = []; } // 添加新房间 public function addRoom() { $this->rooms[] = ['id' => null, 'name' => '']; } // 更新房间数据 public function updateRoom($roomId, $roomName) { foreach ($this->rooms as &$room) { if ($room['id'] == $roomId) { $room['name'] = $roomName; break; } } } public function store() { // 数据验证 $this->validate([ 'address1' => 'required', 'town' => 'required', ]); // 创建/更新房屋 $house = House::updateOrCreate( ['id' => $this->house_id], ['address1' => $this->address1, 'town' => $this->town] ); // 处理房间:删除未保留的房间 if ($this->house_id) { $existingRoomIds = collect($this->rooms)->pluck('id')->filter()->toArray(); Room::where('house_id', $house->id)->whereNotIn('id', $existingRoomIds)->delete(); } // 创建/更新房间 foreach($this->rooms as $room){ if (!empty($room['name'])) { Room::updateOrCreate( ['id' => $room['id']], ['house_id' => $house->id, 'name' => $room['name']] ); } } session()->flash('message', $this->house_id ? '房屋更新成功。' : '房屋创建成功。'); $this->closeModal(); $this->resetInputFields(); } }
4. createHouse视图文件
{{-- views/livewire/houses/createHouse.blade.php --}} <div role="dialog" aria-modal="true" aria-labelledby="modal-headline" @if(!$isOpen) style="display:none;" @endif> <form wire:submit.prevent="store"> <div class="w-1/2 pr-4"> <div class="mb-4"> <label for="input1">地址1:</label> <input type="text" id="input1" placeholder="输入地址" wire:model.defer="address1"> @error('address1') <span class="text-red-500">{{ $message }}</span> @enderror </div> <div class="mb-4"> <label for="input2">城镇:</label> <input type="text" id="input2" placeholder="输入城镇" wire:model.defer="town"> @error('town') <span class="text-red-500">{{ $message }}</span> @enderror </div> </div> <div class="w-1/2"> <h3 class="mb-2">房间</h3> @foreach ($rooms as $key => $room) <div class="mb-2"> @livewire('room-show', ['room' => $room], key('room-' . $key)) <button type="button" wire:click="removeRoom({{ $key }})" class="ml-2 text-red-500">删除</button> </div> @endforeach <button type="button" wire:click="addRoom" class="mb-4 text-blue-500">添加房间</button> <span> <button type="submit">保存</button> <button type="button" wire:click="closeModal" class="ml-2">取消</button> </span> </div> </form> </div>
内容的提问来源于stack exchange,提问作者Urbycoz
相关产品推荐
相关产品推荐

