'Livewire retrieve Data from a relation manyToMany

in my blog project using livewire, i have a relationship manyToMany between tables posts & tags using a pivot table call post_tag
when i want to edit a post , in the modal i get all the data from posts table using -> wire:model.defer="post.body" ( we're using the Post model) for the tags, i'm using a foreach to cycling through all the tags but how to get the tags associates to the post ?

Models


namespace App\Models;

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

class Post extends Model
{
    use HasFactory;

    protected $guarded = ['id', 'created_at', 'updated_at'];

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function category()
    {
        return $this->belongsTo(Category::class);
    }

    public function tags()
    {
        return $this->belongsToMany(Tag::class);
    }

    public function comments()
    {
        return $this->hasMany(Comment::class);
    }
}


<?php

namespace App\Models;

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

class Tag extends Model
{
    use HasFactory;

    protected $guarded = ['id', 'created_at', 'updated_at'];

    public function posts()
    {
        return $this->belongsToMany(Post::class);
    }
}

Migration post_tag table


use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

return new class extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::create('post_tag', function (Blueprint $table) {
            $table->id();
            $table->unsignedBigInteger('post_id');
            $table->unsignedBigInteger('tag_id');
            $table->foreign('post_id')->references('id')->on('posts')->onDelete('cascade');
            $table->foreign('tag_id')->references('id')->on('tags')->onDelete('cascade');
            $table->timestamps();
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::dropIfExists('post_tag');
    }
};

class


namespace App\Http\Livewire;

use Livewire\Component;
use App\Models\Post;
use App\Models\Category;
use App\Models\Tag;
use Livewire\WithPagination;
use Livewire\WithFileUploads;

class EditHideForm extends Component
{
    use WithPagination;

    use WithFileUploads;

    public $open = false;
   
    public $post, $image, $identificador;

    public $taggs;


    protected $rules = [
        'post.name' => 'required|max:100',
        'post.slug' => 'required',
        'post.body' => 'required',
        'post.status' => 'required',
        'post.user_id' => 'required',
        'post.category_id' => 'required',
        'post.image'  => 'required',
        'tagss'  => 'required'
    ];

    public function mount(Post $post)
    {
        $this->post = $post;

        $this->tagss = $post->tags->toArray();

        $this->identificador = rand();
        
    }
    

    public function save()
    {
        $this->validate();

        $this->post->save();

        /* codigo para borrar la foto Aqui */

        

        $this->post->tags()->sync($this->tagss);

        $this->reset(['open']);

        $this->emitTo('show-post', 'render');
    }
    
    public function render()
    {
       
        $categories = Category::all();
        $tags = Tag::all();
        return view('livewire.edit-hide-form', compact('categories', 'tags'));
    }
}

View

    <div class="mb-2">
        @auth
        @if (auth()->user()->id === $post->user->id)
        <x-jet-button wire:click="$set('open', true)">
            Editar
        </x-jet-button>
        <x-jet-danger-button>
            Eliminar
        </x-jet-danger-button>
        @endif
        @endauth
    </div>

    <x-jet-dialog-modal wire:model="open" id="commentModal">
        <x-slot name="title">
            <h1 class="text-2xl mb-4">Edita tu post</h1>
        </x-slot>

        <x-slot name="content">
            <div class="max-w-7xl mx-auto sm:px-6 lg:px-8">
                <div class="container bg-white border-b border-gray-200 shadow-lg mx-auto justify-center px-4 py-2 ">
                    <section id="contact-us">
                        <div wire:loading wire:target='image'
                            class="bg-red-100 border border-red-400 text-xl font-normal  max-w-full flex-initial">
                            <div class="py-2">
                                <p class="ml-2">Cargando la imagen</p>
                                <div class="text-sm font-base">
                                    <p class="ml-2">Espero unos instantes mientras termine el proceso...</p>
                                </div>
                            </div>
                        </div>
                        @if ($image)
                        <img class="mb-4" src="{{ $image->temporaryUrl() }}" alt="">

                        @else
                        <img src="{{ Storage::url($post->image) }}" alt="">

                        @endif

                        <input class="hidden" wire:model="id_user" type="text" id="id" name="user_id" value={{
                            Auth::user()->id }}" />


                        <div>
                            <x-jet-label for="name" value="{{ __('Título') }}" />
                            <x-jet-input id="slug-source" class="block mt-1 mb-2 w-full" wire:model.defer="post.name"
                                type="text" name="name" required autofocus autocomplete="name" />
                            <x-jet-input-error for="name" />

                            <x-jet-label for="slug" value="{{ __('Slug') }}" />
                            <x-jet-input id="slug-target" class="block mt-1 w-full" wire:model.defer="post.slug"
                                type="text" name="slug" :value="old('slug')" required autofocus autocomplete="slug" />
                            <x-jet-input-error for="slug" />
                        </div>


                        <!-- body -->
                        <div>
                            <x-jet-label for="body" class="mt-4 text-base" value="{{ __('Contenido del post') }}" />
                            <textarea wire:model.defer="post.body" id="editor" rows="8" name="body"></textarea>
                        </div>
                        <x-jet-input-error for="body" />


                        <div class="mt-2 center justify-center mx-auto">
                            <!-- Image -->
                            <x-jet-label for="url" value="{{ __('Imagen') }}" />
                            <input type="file" id="image" name="image" class="mb-2" wire:model.defer="post.image" />
                            <x-jet-input-error for="image" />

                        </div>
                        <div>
                            <!-- Drop Down-->
                            <x-jet-label for="categories" value="{{ __('Categoría') }}" />
                            <select name="category_id" class="block font-medium text-sm text-gray-700" id="categories"
                                wire:model.defer="post.category_id">
                                <option selected disabled>opciones </option>
                                @foreach($categories as $category)
                                <option value="{{ $category->id }}">{{ $category->name }}</option>
                                @endforeach
                            </select>

                        </div>
                        <br>

                        <div>
                            <x-jet-label for="tags" value="{{ __('Etiquetas') }}" />

                            @foreach ($tags as $tag)
                            <label for="tagss"
                                class="relative flex-inline items-center isolate p-2 mr-4 mb-2 rounded-2xl">
                                <input wire:model.defer="tagss" value={{ $tag->id }} type="checkbox" class="relative
                                peer z-20 text-blue-600 rounded-md focus:ring-0" />
                                <span class="ml-1 relative z-20">{{ $tag->name }}</span>
                            </label>
                            @endforeach

                        </div>

                        <br>

                        <x-jet-label for="status" value="{{ __('Status') }}" />

                        <div class="flex">
                            <div class="inline-block rounded-lg">
                                Borrador <input type="radio" value=1 wire:model.defer="post.status" id="borrador" />

                            </div>
                            <div class="inline-block rounded-lg ml-4">
                                Publicado <input type="radio" value=2 wire:model.defer="post.status" name="publicado"
                                    id="publicado" />
                            </div>
                        </div>

                    </section>
                </div>
            </div>
        </x-slot>

        <x-slot name='footer'>
            <x-jet-secondary-button wire:click="$set('open', false)">
                Cancelar
            </x-jet-secondary-button>

            <x-jet-danger-button wire:click="save">
                Actualizar
            </x-jet-danger-button>
        </x-slot>

    </x-jet-dialog-modal>


    @push('js')
    <script src="https://cdn.ckeditor.com/ckeditor5/34.0.0/classic/ckeditor.js"></script>

    <script>
        ClassicEditor
                .create( document.querySelector( '#editor' ) )
                .then(function(editor){
                    editor.model.document.on('change:data', () => {
                        @this.set('body', editor.getData());
                    })
                })
                .catch( error => {
                    console.error( error );
                } );
    </script>

    @endpush

</div>

I would appreciate any help or advice, thanks



Solution 1:[1]

Charles, I wrote a POC (Proof of concept) for this problem and just found that it's related to a typo, haha.

You have the public property taggs and then you're assigning $this->tagss, that's why livewire wasn't rendering the checkboxes correctly.

I would recommend you to switch to a more verbose property like tagsSelected instead of taggs (or tagss).

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 itepifanio