无法将具有特征的父组件中的选定数据数组传递给嵌套组件

Posted

技术标签:

【中文标题】无法将具有特征的父组件中的选定数据数组传递给嵌套组件【英文标题】:Unable to pass an array of selected data from parent component with traits to the nested component 【发布时间】:2021-04-28 14:57:54 【问题描述】:

应用结构

App/Http/Livewire
    UserController - Livewire/UserManagement/UserController WithBulkActions - Livewire/Traits/DataTable/WithBulkActions
资源/视图/livewire
    UserController Blade - livewire/user-management/user-controller

说明

我正在创建一个 CRUD 系统,其中包含用于删除所选数据的批量操作。我已经提取了负责选择多个项目或选择当前数据表(即 UserController)中的所有项目的逻辑,因此我可以在其他数据表组件中将其用作特征,即 WithBulkActions。该特征只负责选择多个项目或从数据表中选择所有项目。删除数据数组的公共函数方法存在于数据表组件控制器本身,即 UserController。现在,为了使带有批量操作的多项选择起作用,我必须在数据表组件刀片视图(即 UserController Blade)中包含确认模式,它负责触发删除数据数组的方法。当我包含确认模式以删除用户控制器内的选定数据时,它可以完美运行。虽然每一行都有一个复选框,在 foreach 循环中使用 value=" $user->id " 建模为 wire:model="selected"。公共变量 selected 在 trait WithBulkActions 中初始化为 public $selected = [];,然后在组件 UserController 中使用该 trait。

UserController 组件中的rowsQuery 属性在使用过滤器的查询中从 User 模型中获取数据,对其进行排序并将其作为属性返回。

public function getRowsQueryProperty()
    
        $query = User::query()
            ->when($this->filters['email'], fn($query, $email) => $query->where('email', 'like', '%'.$email.'%'))
            ->when($this->filters['role'], fn($query, $role) => $query->whereHas('roles', fn ($query) => $query->where('id', $role)))
            ->when($this->filters['search'], fn($query, $search) => $query->where('name', 'like', '%'.$search.'%'))
            ->when($this->filters['date-min'], fn($query, $created_at) => $query->where('created_at', '>=', Carbon::createFromFormat('d/m/Y', $created_at)))
            ->when($this->filters['date-max'], fn($query, $created_at) => $query->where('created_at', '<=', Carbon::createFromFormat('d/m/Y', $created_at)));
        
        return $this->applySorting($query);
    

然后将rowsQuery 克隆到特征WithBulkActions 内的selectedRowsQuery 属性中。

public function getSelectedRowsQueryProperty()
    
        return (clone $this->rowsQuery)
            ->unless($this->selectAll, fn($query) => $query->whereKey($this->selected));
    

如果选择了一个数据数组并且要删除选择的数据,则public function confirmDeleteBulk()负责它,它在UserController组件中,以下公共函数调用selectedRowsQuery属性,该属性在trait 本身,然后它执行 delete() 方法并相应地通知。

public function confirmDeleteBulk()
    
        $deleteCount = $this->selectedRowsQuery->count();
        foreach ($this->selectedRowsQuery->get() as $queryRow) 
            $queryRow->roles()->detach();
        
        $this->selectedRowsQuery->delete();
        $this->showUserBulkDeletionModal = false;
        $this->notify('You\'ve deleted '.$deleteCount.' users');
    

我尝试使用公共函数方法制作一个单独的 livewire 组件,以通过显示确认模式来删除选定的数据,但我无法将选定的行数传递给位于 Livewire/UserManagement/LogicalComponent/UserBulkDeletion 的 UserBulkDeletion 嵌套组件.请告诉我在这种情况下最好的用例,以防我想要的。非常感谢您的帮助,因为我从 2 周以来一直在尝试这样做。

上下文

Livewire 版本:2.3.8 Laravel 版本:8.24.0 高山版本:2.8.0 浏览器:Chrome

编辑

Livewire/UserManagement/UserController
class UserController extends Component

    use WithCachedRows, WithSorting, WithBulkActions, WithPerPagePagination;

    public User $user;
    public $showFilters = false;
    public $filters = [
        'search' => "",
        'email' => null,
        'role' => '',
        'date-min' => null,
        'date-max' => null,
    ];

    protected $listeners = ['sectionRefresh' => '$refresh'];

    public function toggleShowFilters()
    
        $this->useCachedRows();

        $this->showFilters = ! $this->showFilters;
    

    public function resetFilters() 
    
        $this->reset('filters'); 
    

    public function updatedFilters() 
    
        $this->resetPage();
    
    
    public function getRowsQueryProperty()
    
        $query = User::query()
            ->when($this->filters['email'], fn($query, $email) => $query->where('email', 'like', '%'.$email.'%'))
            ->when($this->filters['role'], fn($query, $role) => $query->whereHas('roles', fn ($query) => $query->where('id', $role)))
            ->when($this->filters['search'], fn($query, $search) => $query->where('name', 'like', '%'.$search.'%'))
            ->when($this->filters['date-min'], fn($query, $created_at) => $query->where('created_at', '>=', Carbon::createFromFormat('d/m/Y', $created_at)))
            ->when($this->filters['date-max'], fn($query, $created_at) => $query->where('created_at', '<=', Carbon::createFromFormat('d/m/Y', $created_at)));
        
        return $this->applySorting($query);
    

    public function getRowsProperty()
    
        return $this->cache(function () 
            return $this->applyPagination($this->rowsQuery);
        );
    

    public function getRolesProperty()
    
        $roles = Role::all();
        return $roles;
    
    
    public function render()
    
        return view('livewire.backend.management.audience-management.user-controller', ['users' => $this->rows, 'roles' => $this->roles]);
    

Livewire/UserManagement/LogicalComponent/UserBulkDeletion
class UserBulkDeletion extends Component

    use WithCachedRows, WithBulkActions, WithSorting;
    
    public $showUserBulkDeletionModal = false;
    public User $user;
    public $filters = [
        'search' => "",
        'email' => null,
        'role' => '',
        'date-min' => null,
        'date-max' => null,
    ];

    protected $listeners = ['deleteUserBulk'];

    public function deleteUserBulk()
    
        $this->useCachedRows();

        $this->showUserBulkDeletionModal = true;
    

    public function confirmDeleteBulk()
    
        $deleteCount = $this->selectedRowsQuery->count();
        
        foreach ($this->selectedRowsQuery->get() as $queryRow) 
            $queryRow->roles()->detach();
        

        $this->selectedRowsQuery->delete();
        $this->showUserBulkDeletionModal = false;

        $this->notify('You\'ve deleted '.$deleteCount.' users');
        $this->emit('sectionRefresh');
    

    public function getRowsQueryProperty()
    
        $query = User::query()
            ->when($this->filters['email'], fn($query, $email) => $query->where('email', 'like', '%'.$email.'%'))
            ->when($this->filters['role'], fn($query, $role) => $query->whereHas('roles', fn ($query) => $query->where('id', $role)))
            ->when($this->filters['search'], fn($query, $search) => $query->where('name', 'like', '%'.$search.'%'))
            ->when($this->filters['date-min'], fn($query, $created_at) => $query->where('created_at', '>=', Carbon::createFromFormat('d/m/Y', $created_at)))
            ->when($this->filters['date-max'], fn($query, $created_at) => $query->where('created_at', '<=', Carbon::createFromFormat('d/m/Y', $created_at)));
        
        return $this->applySorting($query);
    

    public function render()
    
        return view('livewire.backend.management.audience-management.logical-component.user-bulk-deletion');
    

Livewire/Traits/DataTable/WithBulkActions
trait WithBulkActions

    public $selectPage = false;
    public $selectAll = false;
    public $selected = [];

    public function renderingWithBulkActions()
    
        if ($this->selectAll) $this->selectPageRows();
    

    public function updatedSelected()
    
        $this->selectAll = false;
        $this->selectPage = false;
    

    public function updatedSelectPage($value)
    
        if ($value) return $this->selectPageRows();

        $this->selectAll = false;
        $this->selected = [];
    

    public function selectPageRows()
    
        $this->selected = $this->rows->pluck('id')->map(fn($id) => (string) $id);
    

    public function selectAll()
    
        $this->selectAll = true;
    

    public function getSelectedRowsQueryProperty()
    
        return (clone $this->rowsQuery)
            ->unless($this->selectAll, fn($query) => $query->whereKey($this->selected));
    

views/livewire/user-management/logical-component/user-bulk-deletion
<div>
    <form wire:submit.prevent="confirmDeleteBulk">
        <x-modal.confirmation wire:model.defer="showUserBulkDeletionModal">
            <x-slot name="title">Delete User</x-slot>

            <x-slot name="content">
                @json($selected)
                Are you sure you want to delete users? This action is irreversible!
            </x-slot>

            <x-slot name="footer">
                <x-button.secondary wire:click="$set('showUserBulkDeletionModal', false)">Cancel</x-button.primary>

                <x-button.primary type="submit">Delete</x-button.primary>
            </x-slot>
        </x-modal.confirmation>
    </form>
</div>

【问题讨论】:

【参考方案1】:

要将值从一个 Livewire 组件传递到另一个组件,请使用 events。

Livewire 组件可以通过全局事件系统相互通信。只要两个 Livewire 组件位于同一页面上,它们就可以使用事件和侦听器进行通信。

在您的 Livewire 组件之一中,您会触发类似的事件

$this->event('usersToDelete', [ 1,2,3 ]);

在另一个组件中你可以监听这个事件

public class MyOtherComponent extends Component


    protected $listeners = [
      'usersToDelete' => 'deleteUsers'
    ];

    public function deleteUsers(array $user)
    
      // .. do something
    


【讨论】:

我需要将在特征中初始化的$selected = [] 传递给批量删除组件。因为用户选择的任何内容都存储在变量$selected 中,该变量定义为[]。我发出以下事件wire:click="$emit('deleteUserBulk')" 以显示给批量删除组件。我怎样才能通过$selectedwire:click="$emit('deleteUserBulk')" wire:click="$emit('deleteUserBulk', $selected)"... 请试试这个。还有一个Github issue 描述了如何传递一个/多个参数。 为什么我没有定义$selected,因为我已经在特征 WithBulkActions 中定义了它们,并且我在 BulkDeletion 组件和 UserController 组件中使用了该特征,所以为什么它会抛出这种错误,Uncaught ReferenceError: $selected is not defined 有什么线索吗? 您能否在您的原始帖子中展示 complete Livewire 组件和您的 complete 特征? 嘿,已经完成了,抱歉冗长的代码?

以上是关于无法将具有特征的父组件中的选定数据数组传递给嵌套组件的主要内容,如果未能解决你的问题,请参考以下文章

如何将对象数组作为道具传递给组件,然后将数组的成员作为道具传递给嵌套组件?

将状态传递给 React/Redux 中的递归嵌套组件

angularJS 1.5 嵌套组件

在使用上下文调用 Api 后将数组传递给其他组件

子视图组件将道具传递给Vue中的父布局

将 Angular Reactive FormControls 传递给子组件