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

Livewire PowerGrid批量操作报错:window.pgBulkActions未定义

Laravel 11 + Livewire 3 + PowerGrid 批量操作报错:window.pgBulkActions is undefined

环境与问题概述

  • 技术栈:Laravel 11、Livewire 3(默认集成Alpine)、最新版PowerGrid
  • 表格核心功能(渲染、筛选、分页)正常运行
  • 组件通过php artisan powergrid:create生成,已启用自动Eloquent构建、自动模型发现及可填充属性
  • 开启批量选择(showCheckBox())后,触发批量操作时控制台报错:Alpine Expression Error: window.pgBulkActions is undefined,该全局变量用于存储PowerGrid选中行的ID

组件代码

<?php

namespace App\Livewire;

use App\Models\Department;
use App\Models\OrderItemQuantity;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\Lang;
use PowerComponents\LivewirePowerGrid\Button;
use PowerComponents\LivewirePowerGrid\Column;
use PowerComponents\LivewirePowerGrid\Facades\Filter;
use PowerComponents\LivewirePowerGrid\Footer;
use PowerComponents\LivewirePowerGrid\Header;
use PowerComponents\LivewirePowerGrid\PowerGrid;
use PowerComponents\LivewirePowerGrid\PowerGridFields;
use PowerComponents\LivewirePowerGrid\PowerGridComponent;
use Livewire\Attributes\On;

final class OrderItemQuantityTable extends PowerGridComponent
{
    public bool $showFilters = false;

    public bool $deferLoading = true;

    public string $tableName = 'order_item_quantities';

    public int $stage = 0;

    public function setUp(): array
    {
        $this->showCheckBox();

        return [
            Header::make()->showSearchInput(),
            Footer::make()
                ->showPerPage()
                ->showRecordCount(),
        ];
    }

    public function header(): array
    {
        return [
            Button::add('bulk-delete')
                ->slot('Bulk delete (<span x-text="window.pgBulkActions.count(\'' . $this->tableName . '\')"></span>)')
                ->class('pg-btn-white dark:ring-pg-primary-600 dark:border-pg-primary-600 dark:hover:bg-pg-primary-700 dark:ring-offset-pg-primary-800 dark:text-pg-primary-300 dark:bg-pg-primary-700')
                ->dispatch('bulkDelete.' . $this->tableName, []),
        ];
    }

    public function datasource(): Builder
    {
        return OrderItemQuantity::query()->with('department')
            ->when(
                $this->stage,
                fn ($builder) => $builder->whereHas(
                    'department',
                    fn ($builder) => $builder->where('stage', $this->stage)
                )
            );
    }

    public function relationSearch(): array
    {
        return [
            'department' => [
                'name',
            ],
        ];
    }

    public function fields(): PowerGridFields
    {
        return PowerGrid::fields()
            ->add('id')
            ->add(OrderItemQuantity::MAGENTO_ORDER_ID)
            ->add(OrderItemQuantity::MAGENTO_ITEM_ID)
            ->add(OrderItemQuantity::SKU)
            ->add(OrderItemQuantity::QUANTITY, fn ($orderItemQuantity) => OrderItemQuantity::ITEM_QTY_VIEW_PREFIX.$orderItemQuantity->{OrderItemQuantity::QUANTITY})
            ->add(OrderItemQuantity::DEPARTMENT_ID, fn ($orderItemQuantity) => intval($orderItemQuantity->{OrderItemQuantity::DEPARTMENT_ID}))
            ->add('department_name', fn ($orderItemQuantity) => $orderItemQuantity->{OrderItemQuantity::DEPARTMENT_ID} ? $orderItemQuantity->department->{Department::NAME} : '')
            ->add(OrderItemQuantity::STATUS, fn ($orderItemQuantity) => $orderItemQuantity->{OrderItemQuantity::STATUS} ? OrderItemQuantity::PROCESSING_STAGE_STATUS_OPTION[$orderItemQuantity->{OrderItemQuantity::STATUS}] : '');
    }

    public function columns(): array
    {
        return [
            Column::make('Id', 'id')->sortable(),
            Column::make(Lang::get('common.magento_order_id'), OrderItemQuantity::MAGENTO_ORDER_ID)
                ->sortable()
                ->searchable(),

            Column::make(Lang::get('common.magento_item_id'), OrderItemQuantity::MAGENTO_ITEM_ID)
                ->sortable()
                ->searchable(),

            Column::make(Lang::get('common.sku'), OrderItemQuantity::SKU)
                ->sortable()
                ->searchable(),

            Column::make(Lang::get('common.quantity'), OrderItemQuantity::QUANTITY),

            Column::make(Lang::get('common.department'), 'department_name'),

            Column::make(Lang::get('common.status'), OrderItemQuantity::STATUS),

            Column::action(Lang::get('common.action'))
        ];
    }

    public function filters(): array
    {
        return [
            Filter::inputText(OrderItemQuantity::SKU)
                ->operators(['contains'])
                ->placeholder(Lang::get('common.sku')),

            Filter::inputText(OrderItemQuantity::MAGENTO_ORDER_ID)
                ->operators(['contains'])
                ->placeholder(Lang::get('common.magento_order_id')),

            Filter::inputText(OrderItemQuantity::MAGENTO_ITEM_ID)
                ->operators(['contains'])
                ->placeholder(Lang::get('common.magento_item_id')),

            Filter::select('department_name', OrderItemQuantity::DEPARTMENT_ID)
            ->dataSource(Department::all())
            ->optionLabel('name')
            ->optionValue('id'),

            Filter::select(OrderItemQuantity::STATUS, OrderItemQuantity::STATUS)
            ->dataSource(OrderItemQuantity::PROCESSING_STAGE_STATUS_OPTION_GRID)
            ->optionLabel('name')
            ->optionValue('id'),
        ];
    }

    #[On('edit')]
    public function edit($rowId): void
    {
        $this->js('alert('.$this->tableName.')');
    }

    public function actions(OrderItemQuantity $row): array
    {
        return [
            Button::add('edit')
                ->slot('Edit: '.$row->id)
                ->id()
                ->class('pg-btn-white dark:ring-pg-primary-600 dark:border-pg-primary-600 dark:hover:bg-pg-primary-700 dark:ring-offset-pg-primary-800 dark:text-pg-primary-300 dark:bg-pg-primary-700')
                ->dispatch('edit', ['rowId' => $row->id])
        ];
    }

    #[On('bulkDelete.{tableName}')]
    public function bulkDelete(): void
    {
        $this->js('alert(window.pgBulkActions.get(\'' . $this->tableName . '\'))');
    }

    /*
    public function actionRules($row): array
    {
    return [
            // Hide button edit for ID 1
            Rule::button('edit')
                ->when(fn($row) => $row->id === 1)
                ->hide(),
        ];
    }
    */
}

排查与解决方法

1. 确认PowerGrid资源加载状态

PowerGrid依赖自身的JS资源初始化pgBulkActions,需确保资源正常加载:

  • 检查页面源码,确认存在pg-bulk-actions.js相关脚本
  • 临时关闭延迟加载(将$deferLoading设为false),验证是否为延迟加载导致JS初始化不及时
  • 执行php artisan powergrid:publish发布官方资源,在布局文件中手动添加@powerGridScripts指令,强制引入所需脚本

2. 检查表名一致性

  • 确保组件中$tableName的值与PowerGrid内部绑定的表名完全一致,避免全局变量查找失败
  • 验证批量操作的事件名与监听器匹配:dispatch('bulkDelete.' . $this->tableName)和#[On('bulkDelete.{tableName}')]需保证表名变量解析正确

3. 修复Alpine表达式语法错误

原批量按钮的slot中,字符串转义可能导致Alpine无法正确解析表达式,建议修改为:

->slot("Bulk delete (<span x-text=\"window.pgBulkActions.count('{$this->tableName}')\"></span>)")

或使用Blade渲染语法:

use Illuminate\Support\Facades\Blade;

// ...

->slot(Blade::render('Bulk delete (<span x-text="window.pgBulkActions.count(\':tableName\')"></span>)', ['tableName' => $this->tableName]))

4. 替换为PowerGrid内置批量属性

无需依赖全局window.pgBulkActions,直接使用PowerGrid组件提供的checkboxValues属性获取选中ID,修改批量操作方法:

#[On('bulkDelete.{tableName}')]
public function bulkDelete(): void
{
    $selectedIds = $this->checkboxValues;
    $this->js('alert(' . json_encode($selectedIds) . ')');
}

此方法更稳定,避免全局变量依赖问题。

5. 排查全局变量冲突

检查项目中是否有自定义JS代码覆盖或删除了window.pgBulkActions变量,可在浏览器控制台执行console.log(window.pgBulkActions)验证变量是否存在。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 00:07:03