I am working on a blogging application in Laravel 8.
There is the option to add tags to articles. There is a many-to-many relationship between articles and tags. I have an article_tag
pivot table.
In the Tag
model I have:
class Tag extends Model
{
use HasFactory;
protected $fillable = ['name'];
public function articles()
{
return $this->belongsToMany(Article::class);
}
}
To the Article
model I have added the tags()
method
public function tags()
{
return $this->belongsToMany(Tag::class)->as('tags');
}
I the ArticleController controller, I have two methods for editing and updating an article:
public function edit($id)
{
$article = Article::find($id);
$attached_tags = $article->tags()->get()->pluck('id')->toArray();
return view(
'dashboard/edit-article',
[
'categories' => $this->categories(),
'tags' => $this->tags(),
'attached_tags' => $attached_tags,
'article' => $article
]
);
}
public function update(Request $request, $id)
{
$validator = Validator::make($request->all(), $this->rules, $this->messages);
if ($validator->fails()) {
return redirect()->back()->withErrors($validator->errors())->withInput();
}
$fields = $validator->validated();
$article = Article::find($id);
// If a new image is uploaded, set it as the article image
// Otherwise, set the old image...
if (isset($request->image)) {
$imageName = md5(time()) . Auth::user()->id . '.' . $request->image->extension();
$request->image->move(public_path('images/articles'), $imageName);
} else {
$imageName = $article->image;
}
$article->title = $request->get('title');
$article->short_description = $request->get('short_description');
$article->category_id = $request->get('category_id');
$article->tags[] = $request->get('tags[]');
$article->featured = $request->has('featured');
$article->image = $request->get('image') == 'default.jpg' ? 'default.jpg' : $imageName;
$article->content = $request->get('content');
// Save changes to the article
$article->save();
//Attach tags to article
if (isset($request->tags)) {
$article->tags()->sync($request->tags);
} else {
$article->tags()->sync([]);
}
return redirect()->route('dashboard.articles')->with('success', 'The article titled "' . $article->title . '" was updated');
}
In edit-article.blade.php
, I use a multiselect element to assign tags to articles:
<div class="row mb-2">
<label for="tags" class="col-md-12">{{ __('Tags') }}</label>
<select name="tags[]" id="tags" class="form-control" multiple="multiple">
@foreach ($tags as $tag)
<option value="{{ $tag->id }}"
{{ in_array($tag->id, $attached_tags) ? 'selected' : '' }}>{{ $tag->name }}</option>
@endforeach
</select>
</div>
The problem I am faced with is that when I edit the tags list, the <select>
element above does not keep the selected tags if the form is invalid because of validation errors on other form fields.
Where is my mistake?
I am working on a blogging application in Laravel 8.
There is the option to add tags to articles. There is a many-to-many relationship between articles and tags. I have an article_tag
pivot table.
In the Tag
model I have:
class Tag extends Model
{
use HasFactory;
protected $fillable = ['name'];
public function articles()
{
return $this->belongsToMany(Article::class);
}
}
To the Article
model I have added the tags()
method
public function tags()
{
return $this->belongsToMany(Tag::class)->as('tags');
}
I the ArticleController controller, I have two methods for editing and updating an article:
public function edit($id)
{
$article = Article::find($id);
$attached_tags = $article->tags()->get()->pluck('id')->toArray();
return view(
'dashboard/edit-article',
[
'categories' => $this->categories(),
'tags' => $this->tags(),
'attached_tags' => $attached_tags,
'article' => $article
]
);
}
public function update(Request $request, $id)
{
$validator = Validator::make($request->all(), $this->rules, $this->messages);
if ($validator->fails()) {
return redirect()->back()->withErrors($validator->errors())->withInput();
}
$fields = $validator->validated();
$article = Article::find($id);
// If a new image is uploaded, set it as the article image
// Otherwise, set the old image...
if (isset($request->image)) {
$imageName = md5(time()) . Auth::user()->id . '.' . $request->image->extension();
$request->image->move(public_path('images/articles'), $imageName);
} else {
$imageName = $article->image;
}
$article->title = $request->get('title');
$article->short_description = $request->get('short_description');
$article->category_id = $request->get('category_id');
$article->tags[] = $request->get('tags[]');
$article->featured = $request->has('featured');
$article->image = $request->get('image') == 'default.jpg' ? 'default.jpg' : $imageName;
$article->content = $request->get('content');
// Save changes to the article
$article->save();
//Attach tags to article
if (isset($request->tags)) {
$article->tags()->sync($request->tags);
} else {
$article->tags()->sync([]);
}
return redirect()->route('dashboard.articles')->with('success', 'The article titled "' . $article->title . '" was updated');
}
In edit-article.blade.php
, I use a multiselect element to assign tags to articles:
<div class="row mb-2">
<label for="tags" class="col-md-12">{{ __('Tags') }}</label>
<select name="tags[]" id="tags" class="form-control" multiple="multiple">
@foreach ($tags as $tag)
<option value="{{ $tag->id }}"
{{ in_array($tag->id, $attached_tags) ? 'selected' : '' }}>{{ $tag->name }}</option>
@endforeach
</select>
</div>
The problem I am faced with is that when I edit the tags list, the <select>
element above does not keep the selected tags if the form is invalid because of validation errors on other form fields.
Where is my mistake?
Share Improve this question edited Feb 18 at 6:22 Abdulla Nilam 38.6k18 gold badges68 silver badges95 bronze badges Recognized by PHP Collective asked Feb 17 at 22:19 Razvan ZamfirRazvan Zamfir 4,6667 gold badges47 silver badges282 bronze badges1 Answer
Reset to default 1There are few errors in this (optimizations too)
Remove this line
$article->tags[] = $request->get('tags[]'); // $article->tags()->sync will do the job
Change this
if ($request->has('tags')) { # changed $article->tags()->sync($request->tags); } else { $article->tags()->sync([]); }
In view
@php // Use old input if present, otherwise use the attached tags from the article. $selectedTags = old('tags', $attached_tags); @endphp <div class="row mb-2"> <label for="tags" class="col-md-12">{{ __('Tags') }}</label> <select name="tags[]" id="tags" class="form-control" multiple="multiple"> @foreach ($tags as $tag) <option value="{{ $tag->id }}" {{ in_array($tag->id, $selectedTags) ? 'selected' : '' }}> {{ $tag->name }} </option> @endforeach </select> </div>