【问题标题】:how to display many to many relationship data in laravel livewire?如何在 laravel livewire 中显示多对多关系数据?
【发布时间】:2021-08-25 11:55:24
【问题描述】:

大家晚安。当我想显示多对多关系数据时遇到问题,即基于带有 livewire 的标签的邮政数据。以前我在laravel里试过可以出现。

现在我想用livewire按标签显示帖子数据,但还是不行。

以下是我自己做的代码。

web.php

Route::get('tag/{tag:slug}',[FrontController::class, 'tag'])->name('tag');

FrontController.php

public function tag(Tag $tag)
    {
        $categories = Category::all();
        $general = General::find(1);
        $locale = App::currentLocale();

        $search = request("search");
       
        $posts = $tag->posts()->where([
            ['status','PUBLISH'],
            ['lang',$locale],
        ])->latest()->paginate(12);

        if ($this->search !== null) {
            $posts = $tag->posts()->where([
                ['title','like', '%' . $search . '%'],
                ['lang',$locale],
                ['status','PUBLISH'],
            ])->latest()->paginate(12);
        }

        // dd($posts);

        $tags = Tag::all();
        $top        = Post::where('status','PUBLISH')->orderBy('views','desc')->limit(5)->get();
        return view ('front.tag',compact('categories','general','locale','posts','tags','top'));
    }

tag.blade.php

@extends('layouts.front')

@section('content')
<main id="main">
    <section class="post-category">
        <div class="container-fluid">
            <div class="row mt-3">
                <div class="col-lg-3 col-md-12 col-sm-12 d-none d-lg-block">
                    <div class="sticky-top" style="top: 90px;">
                        <div class="card mb-3 rounded-3">
                            <div class="card-body">
                                <a href="#" target="_blank" rel="noreferrer">
                                    <img src="{{ asset('front/img/ads.png') }}" alt="..." height="300" width="279" class="card-img-top" />
                                </a>
                            </div>
                        </div>
                        <div class="d-flex flex-column mb-3 bg-light shadow bg-body rounded">
                            <div class="card-header bg-primary bg-gradient text-white fw-bold fs-5">
                                {{ __('sentence.category') }}
                            </div>
                            <ul class="list-group list-group-flush">
                                @foreach ($categories as $category)
                                    <li class="list-group-item d-flex justify-content-between align-items-center">
                                        <a href="{{ route('category', $category->slug) }}">{{ $category->name }}</a>
                                    </li>
                                @endforeach
                            </ul>
                        </div>
                        <div class="d-flex flex-column bg-light bg-body shadow-lg rounded-3">
                            <div class="card-header bg-primary bg-gradient text-white fw-bold fs-5">
                                Tags
                            </div>
                            <div class="p-3 overflow-auto" style="max-height: 42vh">
                                <div class="nav tag-cloud">
                                    @foreach ($tags as $tag)
                                        <a href="{{ route('tag', $tag->slug) }}">{{ $tag->name }}</a>
                                    @endforeach   
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
    
                <livewire:tag-index>
                
                <div class="col-lg-3 col-md-12 col-sm-12">
                    <div class="sticky-top" style="top: 90px;">
                        <div class="card rounded-3 shadow-lg mb-3">
                            <div class="card-body">
                                <img src="{{ asset('front/img/ads1.png') }}" height="117" width="279" class="card-img-top" alt="...">
                            </div>
                        </div>
                        <div class="bg-light shadow bg-body rounded-3 mb-3">
                            <div class="card-header bg-primary bg-gradient text-white fw-bold fs-5">
                                {{ __('sentence.top_article') }}
                            </div>
                            <ul class="list-group list-group-flush mb-2">
                                @foreach ($top as $top)
                                <li class="list-group-item">
                                    <a href="{{ route('blogShow', $top->slug) }}">{{ $top->title }}</a>
                                    <div class="d-flex justify-content-between mt-3">
                                        <small class="text-muted">{{ Carbon\Carbon::parse($top->created_at)->format("d F, Y") }}</small>
                                        <small class="text-muted">{{ $top->views }} views </small>
                                    </div>
                                </li>
                                @endforeach
                            </ul>
                        </div>
                        <div class="d-flex flex-column mb-3 bg-light shadow bg-body rounded d-lg-none d-xl-none">
                            <div class="card-header bg-primary bg-gradient text-white fw-bold fs-5">
                                {{ __('sentence.category') }}
                            </div>          
                            <ul class="list-group list-group-flush">
                                @foreach ($categories as $category)
                                    <li class="list-group-item d-flex justify-content-between align-items-center">
                                        <a href="{{ route('category', $category->slug) }}">{{ $category->name }}</a>
                                    </li>
                                @endforeach
                            </ul>
                        </div>
                        <div class="d-flex flex-column bg-light bg-body shadow-lg rounded-3 d-lg-none d-xl-none">
                            <div class="card-header bg-primary bg-gradient text-white fw-bold fs-5">
                                {{ __('sentence.tag') }}
                            </div>
                            <div class="p-3 overflow-auto" style="max-height: 42vh">
                                <div class="nav tag-cloud">
                                    @foreach ($tags as $tag)
                                        <a href="{{ route('tag', $tag->slug) }}">{{ $tag->name }}</a>
                                    @endforeach   
                                </div>
                            </div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </section>
</main>
@endsection

@push('scripts')
@livewireScripts
<script type="text/javascript">
    window.onscroll = function (ev) {
        if ((window.innerHeight + window.scrollY) >= document.body.offsetHeight) {
            window.livewire.emit('tag-index');
        }
    };

</script>

<script>
    document.getElementById('load-more').onclick = function() {
        window.livewire.emit('tag-index');
    };
</script>
@endpush

livewire\TagIndex.php

<?php

namespace App\Http\Livewire;

use Livewire\Component;
use App\Models\{Tag, Post};
use Illuminate\Support\Facades\App;

class TagIndex extends Component
{
    public $limitPerPage = 10;

    public $search;

    protected $listeners = [
        'tag-index' => 'TagIndex'
    ];

    protected $updatesQueryString = [
        ['search' => ['except' => '']],
    ];
   
    public function TagIndex()
    {
        $this->limitPerPage = $this->limitPerPage + 6;
    }

    public function render(Tag $tag)
    {
        $locale = App::currentLocale();

        $posts = $tag->posts()->where([
            ['status','PUBLISH'],
            ['lang',$locale],
        ])->latest()->paginate($this->limitPerPage);

        if ($this->search !== null) {
            $posts = $tag->posts()->where([
                ['title','like', '%' . $this->search . '%'],
                ['status','PUBLISH'],
                ['lang',$locale],
            ])->latest()->paginate($this->limitPerPage);
        }
        
        $this->emit('postStore');


        return view('livewire.tag-index', ['posts' => $posts]);
    }
}

livewire\tag-index.blade.php

<div class="col-lg-6 col-md-12 col-sm-12">
    <div id="section-title" class="section-title p-1 pt-3">
        <h2 class="text-center fw-bold">{{ trans('sentence.recent_posts')}}</h2>
    </div>
    <div class="form-group has-search mb-3">
        <span class="bi bi-search form-control-feedback"></span>
        <input type="text" wire:model="search" class="form-control" placeholder="{{ __('sentence.search_form') }}">
    </div>
    @foreach ($posts as $data)
    <div class="card bg-light shadow bg-body rounded-3 mb-2">
        <div class="card-header bg-primary text-white d-flex justify-content-between">
            <small>by {{$data->admin->name}}</small>
            <small>{{ Carbon\Carbon::parse($data->created_at)->format("d F, Y") }}</small>
        </div>
        <div class="card-body">
            <h2 class="card-title">
                <a href="{{ route('blogShow', $data->slug) }}">{{ $data->title }}</a>
            </h2>
            <div class="card-footer bg-body d-flex justify-content-between align-items-center pb-0 px-0">
                <div class="d-flex my-1">
                    @foreach ($data->tags as $tag)
                    <a href="{{ route('tag', $tag->slug) }}" class="badge {{ $tag->bg }} me-1 shadow-sm text-white">{{ $tag->name }}</a>
                    @endforeach
                </div>
            </div>
        </div>
    </div>
    @endforeach
    @if ($posts->count() == 0)
    <div class="alert alert-danger" role="alert">
        Data not found!
    </div>
    @endif
    @if($posts->count() >= 10)
    <div class="text-center d-md-none d-lg-none d-xl-none">
        <button id="load-more" class="btn btn-primary my-3">
        Load More
        </button>
    </div>
    @endif
</div>

使用 livewire 显示多对多关系数据的正确方法或代码是什么?在这种情况下,我想按标签显示帖子数据。谢谢

【问题讨论】:

  • 所以你有很多tags,你想显示所有与tag关联的posts,并且有人可以选择多个tags
  • 是的,就像在stackoverflow.com/tags中一样,当我们选择一个javascript标签时,它会显示带有javascript标签的帖子。对于我的数据透视表,已经有一个 post_tag

标签: php laravel laravel-livewire


【解决方案1】:

您的问题中有很多额外的stuff,所以我为您整理了一个简化的示例。您需要完成剩余的工作才能将其纳入您的项目。

我不知道你如何显示你的tag 标签或任何东西,所以我选择了checkboxes,因为这似乎是最明智的。这些可以设置为隐藏,因此它们更类似于 SO 上的 tag 标签,但同样,我将把 bike shedding 留给你。

我创建了一个名为 TagsLivewire component 以及关联的 blade 视图。

tags.blade.php

<div>
    {{-- loop over each of the tags --}}
    @foreach ($this->tags as $tag)
        {{-- wire:key is important here as Livewire requires it for effective DOM diffing! --}}
        <div wire:key="tag-{{ $tag->id }}" class="block px-4 py-2">
            {{-- 
                this is where we bind the checkboxes
                to a property on the Livewire component
            --}}
            <input wire:model="selectedTags" type="checkbox" id="tag-{{ $tag->id }}" name="{{ $tag->title }}" value="{{ $tag->id }}">
            <label for="{{ $tag->title }}">{{ $tag->title }}</label>
        </div>
    @endforeach

    {{-- loop over each of the posts --}}
    @foreach ($this->posts as $post)
        {{-- again, don't overlook wire:key! --}}
        <div wire:key="post-{{ $post->id }}" class="block px-4 py-2">
            <h4 class="text-sm">{{ $post->title }}</h4>
        </div>
    @endforeach
</div>

以上内容大部分应该是不言自明的,唯一可能不是wire:model="selectedTags"。在Tags 组件上定义了一个名为selectedTags 的公共属性(稍后您将看到),它的作用是允许我们在选中其中一个复选框时管理该数组中的元素。因此,例如,当有人使用12id 选中tag 的复选框时,selectedTags 数组添加了一个元素,其中添加了12value

Tags.php

class Tags extends Component
{
    // array of selected tags (checked checkboxes)
    public $selectedTags = [];

    // get just the id and title of each tag
    public function getTagsProperty()
    {
        return Tag::select('id', 'title')->get();
    }

    public function getPostsProperty()
    {
        $tags = array_filter($this->selectedTags);

        // if no tags are selected, return all posts
        // you might decide to return nothing, up to you
        if (!$tags) {
            return Post::all();
        }

        // if there are some selected tags
        // query the database for posts with the selectedTags
        // this is an `OR` operation on tags
        // if you want `AND` you'll need to change it
        return Post::whereHas('tags', function ($query) use ($tags) {
            $query->whereIn('tags.id', $tags);
        })->get();
    }

    public function render()
    {
        return view('livewire.tags');
    }
}

以上内容应该是不言自明的,因为没有什么不寻常的事情发生。

getPostsProperty()getTagsProperty() 函数定义了可选的 computed properties,如果你愿意,你可以使用普通属性。但是,如果您在组件视图中多次引用 $tags$posts,则计算属性的性能会更高,因为它不会每次都调用后端组件。

【讨论】:

    【解决方案2】:

    已解决

    感谢@Peppermintology 帮助我解决了两个问题,现在这个问题已经用下面的代码解决了。

    FrontController.php

     public function tag(Tag $tag)
        {
            $categories = Category::all();
            $general = General::find(1);
            $locale = App::currentLocale();
            $tag_id = $tag->id;
    
            $search = request("search");
           
            $posts = $tag->posts()->where([
                ['status','PUBLISH'],
                ['lang',$locale],
            ])->latest()->paginate(12);
    
            if ($this->search !== null) {
                $posts = $tag->posts()->where([
                    ['title','like', '%' . $search . '%'],
                    ['lang',$locale],
                    ['status','PUBLISH'],
                ])->latest()->paginate(12);
            }
    
            $tags = Tag::all();
            $top        = Post::where('status','PUBLISH')->orderBy('views','desc')->limit(5)->get();
            return view ('front.tag',compact('categories','general','locale','posts','tags','tag_id','top'));
        }
    

    livewire\TagIndex.php

    <?php
    
    namespace App\Http\Livewire;
    
    use Livewire\Component;
    use App\Models\{Tag, Post};
    use Illuminate\Support\Facades\App;
    
    class TagIndex extends Component
    {
        public $limitPerPage = 10;
    
        public $search, $tagId;
    
        protected $listeners = [
            'tag-index' => 'TagIndex'
        ];
    
    
        protected $updatesQueryString = [
            ['search' => ['except' => '']],
        ];
       
        public function TagIndex()
        {
            $this->limitPerPage = $this->limitPerPage + 6;
        }
    
        public function render()
        {
            $locale = App::currentLocale();
            $tag_id = $this->tagId;
    
            $tag = Tag::find($tag_id);  
    
            $posts = $tag->posts()->where([
                ['status','PUBLISH'],
                ['lang',$locale],
            ])->latest()->paginate($this->limitPerPage);
    
            if ($this->search !== null) {
                $posts = $tag->posts()->where([
                    ['title','like', '%' . $this->search . '%'],
                    ['status','PUBLISH'],
                    ['lang',$locale],
                ])->latest()->paginate($this->limitPerPage);
            }
            
            $this->emit('postStore');
    
            // dd($posts);
    
            return view('livewire.tag-index', ['posts' => $posts, 'tag' => $tag]);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-05-06
      • 2020-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-08-07
      相关资源
      最近更新 更多