Our QuickAdminPanel has a belongsToMany relationship field, but we don’t have the ability to add additional columns to the pivot table. Don’t worry, this article will show you how to make these changes manually, or implement them in your Laravel projects that are not created by QuickAdminPanel.
Imagine a scenario: you have a Recipe website, and each Recipe can consist of multiple Ingredients, so you create a many-to-many relationship, and add ingredients with the multiple Select2 dropdowns we generate:
But it makes more sense to add ingredients by QUANTITY, right? So how much of each ingredient do we need in the recipe. For that, we need additional fields recipe_ingredients pivot table.
Let’s apply this in this article, and also change the shape to be able to determine this quantity. Here’s the final result:

Or, if you prefer a video demo:
So, let’s make changes one step at a time.
Step 1. New field Quantity: Migration/Model
From the QuickAdminPanel Generated by default, we have this structure.
app/Models/Recipe.php:
public function ingredients()
{
return $this->belongsToMany(Ingredient::class);
}
Let’s add it amount field here.
php artisan make:migration add_amount_to_ingredient_recipe_table
And in migration:
public function up()
{
Schema::table('ingredient_recipe', function (Blueprint $table) {
$table->string('amount');
});
}
And then we need to define it app/Models/Recipe.php:
public function ingredients()
{
return $this->belongsToMany(Ingredient::class)->withPivot('amount');
}
You can read more about Eloquent’s changes in the official Laravel documentation.
Step 2. Blade+Controller: Create/Edit Form
In the controller, we need to enter the Ingredients make() method:
public function create()
{
return view('admin.recipes.create', [
'ingredients' => Ingredient::all(),
]);
}
And then log in resources/views/admin/recipes/create.blade.phpinstead of that Select2 field, we will create a partial bar that will be reused in the Create and Save views. So these sections will be identical recipes/buat.blade.php And recipes/edit.blade.php:
<div class="form-group">
<label class="required" for="ingredients">{{ trans('cruds.recipe.fields.ingredients') }}</label>
@include('admin.recipes.partials.ingredients')
@if($errors->has('ingredients'))
<div class="invalid-feedback">
{{ $errors->first('ingredients') }}
</div>
@endif
<span class="help-block">{{ trans('cruds.recipe.fields.ingredients_helper') }}</span>
</div>
Now, what’s inside resources/views/admin/recipes/partials/ingredients.blade.php?
<table>
@foreach($ingredients as $ingredient)
<tr>
<td><input {{ $ingredient->value ? 'checked' : null }} data-id="{{ $ingredient->id }}" type="checkbox" class="ingredient-enable"></td>
<td>{{ $ingredient->name }}</td>
<td><input value="{{ $ingredient->value ?? null }}" {{ $ingredient->value ? null : 'disabled' }} data-id="{{ $ingredient->id }}" name="ingredients[{{ $ingredient->id }}]" type="text" class="ingredient-amount form-control" placeholder="Amount"></td>
</tr>
@endforeach
</table>
@section('scripts')
@parent
<script>
$('document').ready(function () {
$('.ingredient-enable').on('click', function () {
let id = $(this).attr('data-id')
let enabled = $(this).is(":checked")
$('.ingredient-amount[data-id="' + id + '"]').attr('disabled', !enabled)
$('.ingredient-amount[data-id="' + id + '"]').val(null)
})
});
</script>
@endsection
So, we are loading $material as a table, checking whether each amount has a value or is set to zero and whether we need to disable that input.
Also, there is @section(‘script’) which adds a jQuery snippet to enable/disable the quantity field on a row, if the multiple ingredients checkbox is checked.
Now, where do we get it from $material->value? In the Recipe Controller method edit()here’s what we have:
public function edit(Recipe $recipe)
{
abort_if(Gate::denies('recipe_edit'), Response::HTTP_FORBIDDEN, '403 Forbidden');
$recipe->load('ingredients');
$ingredients = Ingredient::get()->map(function($ingredient) use ($recipe) {
$ingredient->value = data_get($recipe->ingredients->firstWhere('id', $ingredient->id), 'pivot.amount') ?? null;
return $ingredient;
});
return view('admin.recipes.edit', [
'ingredients' => $ingredients,
'recipe' => $recipe,
]);
}
As you can see, we are using the Collection method map() and then get the value pivot.amount structure.
Step 3. Validate/Save Materials
First, a small change to the default QuickAdminPanel code: we need to change the validation rule: from integers to network here, because our sum is a string.
app/Http/Requests/StoreRecipeRequest.phpand identically UpdateRecipeRequest.php:
public function rules()
{
return [
'name' => [
'string',
'required',
],
'ingredients.*' => [
'string',
],
'ingredients' => [
'required',
'array',
],
];
}
Finally, how we store and update data, in Recipe Controller:
public function store(StoreRecipeRequest $request)
{
$data = $request->validated();
$recipe = Recipe::create($data);
$recipe->ingredients()->sync($this->mapIngredients($data['ingredients']));
return redirect()->route('admin.recipes.index');
}
public function update(UpdateRecipeRequest $request, Recipe $recipe)
{
$data = $request->validated();
$recipe->update($data);
$recipe->ingredients()->sync($this->mapIngredients($data['ingredients']));
return redirect()->route('admin.recipes.index');
}
private function mapIngredients($ingredients)
{
return collect($ingredients)->map(function ($i) {
return ['amount' => $i];
});
}
Again, some of the Collection “magic” in the method map material to make the save/update method easier to read and shorter.
Step 4. Show Ingredients by Amount
A final small change must be made resources/display/admin/recipes/show.blade.php:
<tr>
<th>
{{ trans('cruds.recipe.fields.ingredients') }}
</th>
<td>
@foreach($recipe->ingredients as $key => $ingredients)
<div class="label label-info">{{ $ingredients->name }}
({{ $ingredients->pivot->amount }})</div>
@endforeach
</td>
</tr>
As you can see, we use $ingredients->pivot->amount to indicate the amount of each ingredient.
And that’s it!
You can see the transformation in the public demo repository here.
Teknologi Terkini
Agen Togel Terpercaya
Bandar Togel
Sabung Ayam Online
Berita Terkini
Artikel Terbaru
Berita Terbaru
Penerbangan
Berita Politik
Berita Politik
Software
Software Download
Download Aplikasi
Berita Terkini
News
Jasa PBN
Jasa Artikel
News
Breaking News
Berita