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

Laravel Livewire子表单预填充失败及foreach空值错误求助

表单预填充失败问题修复

问题描述

尝试从数据库记录预填充表单时,子表单无法加载,虽遵循Laravel表结构规范,但仍出现错误:

ErrorException
foreach() argument must be of type array|object, null given

使用dd($allTariffs)能输出数组,但视图中无法显示数据。


相关代码

编辑组件代码

<?php

namespace App\Http\Livewire\Admin;

use App\Models\Products;
use App\Models\Tariffs;
use Livewire\Component;

class AdminEditTariffsComponent extends Component
{
    public $tariffId;
    public $allTariffs = [];
    public $rowProducts = [];
    public $tariffName;
    
    public function mount ($tariffId)
    {
        $this->rowProducts = Products::all();
 
        $tariff = Tariffs::where('id', $tariffId)->first();
        $this->tariffName = $tariff->tariff_name;
       
        $allTariffs = $tariff->products->find($tariffId);
        
        foreach ($allTariffs->products as $product)
        {
            ['productId' => $product->pivot->products_id, 'basicCharge' => $product->pivot->basic_charge, 'additionalCharge' => $product->pivot->additional_charge];
        }
    }

    public function updateStatus()
    {
        $tariff = Tariffs::find($this->tariffId);
        $tariff->tariff_name = $this->tariffName;
        $tariff->created_by = auth()->user()->id;
        $tariff->save();
       
        foreach ($this->allTariffs as $product) {
            $tariff->products()->sync($product['productId'],
                ['basic_charge' => $product['basicCharge'], 
                'additional_charge' => $product['additionalCharge']]);
        }

        session()->flash('message', 'Tariff added successfully!');
        return redirect('/admin/tariffs/');
    }

    public function addProduct()
    {
        $this->allTariffs[] = ['productId' => '', 'basicCharge' => '', 'additionalCharge' => ''];
    }

    public function removeProduct($index)
    {
        unset($this->allTariffs[$index]);
        $this->allTariffs = array_values($this->allTariffs);
    }

    public function render()
    {
        $rowProducts = Products::all();
        return view('livewire.admin.admin-edit-tariffs-component',['rowProducts'=>$rowProducts])->layout('layouts.admin.base');
    }
}

编辑视图代码

<div class="container-fluid">
    <div class="row">
        <div class="col-lg-8">
            <div class="card shadow mb-4">
                <div class="card-header py-3">
                    <h6 class="m-0 font-weight-bold text-primary">Edit Tariff</h6>
                </div>
                <div class="card-body">
                    <form wire:submit.prevent="editTariff">
                        @csrf
                        <div class="form-row">
                            <div class="form-group col-md-8">
                                <input type="text" class="form-control" placeholder="Enter Tariff Name"
                                    wire:model="tariffName" required>
                            </div>
                        </div>
                        <hr>

                        <div class="card">
                            <div class="card-header">
                                <h6 class="text-primary">Products, Basic and Weight Charges</h6>
                            </div>
                            <div class="card-body">
                                <table class="table" id="products_table">
                                    <thead>
                                        <tr>
                                            <th>Product</th>
                                            <th>Basic Charge</th>
                                            <th>Weight Charge</th>
                                            <th></th>
                                        </tr>
                                    </thead>
                                    <tbody>
                                        @foreach ($allTariffs as $index => $allTariff)
                                        <tr wire:key="tariff-{{ $value->wireKey }}">
                                            <td>
                                                <select
                                                    wire:model="allTariffs.{{$index}}.productId"
                                                    class="custom-select custom-select-sm form-control form-control-sm">
                                                    <option value="">Select Product</option>
                                                    @foreach ($rowProducts as $product)
                                                    <option value="{{ $product->id }}">
                                                        {{ $product->product_name }}
                                                    </option>
                                                    @endforeach
                                                </select>
                                            </td>
                                            <td>
                                                <input type="text"
                                                    class="form-control custom-select-sm form-control form-control-sm"
                                                    placeholder="Basic Charge"
                                                    wire:model="allTariffs.{{$index}}.basicCharge" required>
                                            </td>
                                            <td>
                                                <input type="text"
                                                    class="form-control custom-select-sm form-control form-control-sm"
                                                    placeholder="Weight Charge"
                                                    wire:model="allTariffs.{{$index}}.additionalCharge" required>
                                            </td>
                                            <td>
                                                <a href="#" wire:click.prevent="removeProduct({{$index}})" class="btn btn-danger btn-circle btn-sm">
                                                    <i class="fas fa-trash"></i>
                                                </a>
                                            </td>
                                        </tr>
                                        @endforeach
                                    </tbody>
                                </table>
                                <div class="row">
                                    <div class="col-md-12">
                                        <a href="#" wire:click.prevent="addProduct" class="btn btn-success btn-circle btn-sm">
                                            <i class="fas fa-plus"></i>
                                        </a>
                                    </div>
                                </div>
                            </div>
                        </div>

                        <hr>

                        <div class="form-row">
                        <div class="form-group col-md-3"> 
                        <button type="submit" class="form-control btn btn-small btn-primary">Edit
                            Tariff</button>
                        </div>
                    </div>
                    </form>
                </div>
            </div>
        </div>
    </div>
</div>

模型文件代码

<?php

namespace App\Models;

use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;

class Tariffs extends Model
{
    use HasFactory;

    protected $table = "tariffs";

    public function products()
    {
        return $this->belongsToMany(Products::class, 'products_tariffs', 
        'products_id', 'tariffs_id')
            ->withPivot('basic_charge', 'additional_charge');
    }

    public function productstariffs()
    {
        return $this->hasMany(ProductsTariffs::class); 
    }
}

修复步骤

1. 修正模型关联外键顺序

belongsToMany的第三个参数是当前模型在中间表的外键,第四个是关联模型的外键,原代码顺序颠倒,修改如下:

public function products()
{
    return $this->belongsToMany(Products::class, 'products_tariffs', 
    'tariffs_id', 'products_id') // 交换外键顺序
        ->withPivot('basic_charge', 'additional_charge');
}

2. 修复预填充数据逻辑

  • 给组件的$tariffId赋值(updateStatus方法需要用到)
  • 直接获取关联的产品集合,而非错误调用find($tariffId)
  • 将循环生成的数组存入$this->allTariffs(原代码仅创建数组未赋值)

修改后的mount方法:

public function mount ($tariffId)
{
    $this->rowProducts = Products::all();
    $this->tariffId = $tariffId; // 给组件属性赋值

    $tariff = Tariffs::where('id', $tariffId)->firstOrFail(); // 用firstOrFail避免null
    $this->tariffName = $tariff->tariff_name;

    // 获取当前关税关联的所有产品
    $associatedProducts = $tariff->products;

    // 填充allTariffs数组
    foreach ($associatedProducts as $product) {
        $this->allTariffs[] = [
            'productId' => $product->pivot->products_id, 
            'basicCharge' => $product->pivot->basic_charge, 
            'additionalCharge' => $product->pivot->additional_charge
        ];
    }
}

3. 修复视图错误

  • 表单提交方法绑定错误:将wire:submit.prevent="editTariff"改为wire:submit.prevent="updateStatus"(组件中实际方法名是updateStatus)
  • wire:key变量错误:将$value->wireKey改为$index(循环变量是$index,$value未定义)

修改后的视图片段:

<form wire:submit.prevent="updateStatus">
    <!-- ... 其他代码 ... -->
    @foreach ($allTariffs as $index => $allTariff)
    <tr wire:key="tariff-{{ $index }}">
        <!-- ... 其他代码 ... -->
    </tr>
    @endforeach

4. 修正关联同步逻辑

sync方法的第二个参数是$detaching(是否移除未在数组中的关联),而非pivot数据。正确用法是整理成[产品ID => [pivot字段]]的格式后同步:

修改后的updateStatus方法:

public function updateStatus()
{
    $tariff = Tariffs::findOrFail($this->tariffId);
    $tariff->tariff_name = $this->tariffName;
    $tariff->created_by = auth()->user()->id;
    $tariff->save();

    // 整理同步数据格式
    $syncData = [];
    foreach ($this->allTariffs as $product) {
        if (!empty($product['productId'])) { // 跳过未选择产品的空项
            $syncData[$product['productId']] = [
                'basic_charge' => $product['basicCharge'],
                'additional_charge' => $product['additionalCharge']
            ];
        }
    }

    $tariff->products()->sync($syncData);

    session()->flash('message', 'Tariff updated successfully!');
    return redirect('/admin/tariffs/');
}

内容的提问来源于stack exchange,提问作者iDRE

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.21 21:18:39