Livewire从关系中检索数据
在我使用Livewire的博客项目中,我在桌子帖子和amp;使用枢轴表呼叫post_tag的标签
当我想编辑帖子时,在模式中,我使用 - >电线:model.defer =“ post.body”(我们使用的是邮政模型) 对于标签,我正在使用一个foreach来浏览所有标签,但是如何将标签关联到帖子中?
模型
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);
}
}
迁移post_tag表
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'));
}
}
查看
<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>
我感谢任何帮助或建议,谢谢
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
查尔斯,我写了一个poc (概念证明)这与错字有关,哈哈。
您拥有public属性
taggs
,然后分配$ this-&gt; tagss
,这就是为什么LiveWire无法正确渲染复选框的原因。我建议您切换到更详细的属性,例如
tagsselected
而不是taggs
(或tagss
)。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 oftaggs
(ortagss
).