Selecteren - Introductie
De relatie tussen Product en Category gaat op basis van het veld category_id in de products tabel die wijst naar de id in de categories tabel.
In de CREATE en UPDATE formulieren moeten we een waarde ingeven in de category_id. Dat is een integer waarde. De gebruiker van de website weet waarschijnlijk niet wat de getalwaarde is van de categorie "Gereedschap".
We willen de gebruikers hier ook niet mee lastig gaan vallen. We gaan dat voor hen oplossen.
Ik begin met wellicht een vreemd advies. Een deel van de oplossing is het gebruik van de HTML SELECT tag. Die wil soms wel eens vreemd omgaan met foutmeldingen. Die worden namelijk opgegeten en niet weergegeven. Mijn tip is dan ook om eerst de achterkant te bouwen met een input veld. En die dan te vervangen door een SELECT tag.
Formulier
We beginnen met het invoer veld op het formulier te plaatsen.
<p>Categorie<br>
<input type="text" name="category_id" 
        value="{{ old('category_id', $product->category_id) }}"></p>
We beginnen met het invoer veld op het formulier te plaatsen. Als je dit hebt gedaan en je gaat dan een bestaand product wijzigen, dan zul je zien dat de category_id al is ingevuld. Die hebben we immers met het migratie script in de database gezet.
In dit veld kunnen we de integer waarde voor category_id ingeven.
Controller
Nu gaan we ervoor zorgen dat de waarde ook zal worden opgeslagen.
Allereerst gaan we valideren. Hierbij is het belangrijk dat er een category_id is ingegeven, dat is de required optie. Het andere belangrijke punt is dat de ingegeven category_id altijd aanwezig moet zijn in de categories tabel in het veld id. Dit moet altijd zijn. De validatie regel is dus:
'category_id' => 'required|exists:categories,id'
Iets verderop in de code moeten we natuurlijk de waarde vanuit $validated overzetten naar het $product object om op te slaan.
$product->category_id = $validated['category_id'];
Het eerste deel van de code werkt nu helemaal goed. We kunnen een id ingeven, als deze id bestaat dan zal die worden opgeslagen, maar als die niet bestaat dan zal een error volgen.
SELECT tag
In het scherm voorbeeld hierboven vullen we een gedrag in. Dat is dan de category_id. In onze seeder hadden we deze lijst opgenomen.
id=1        name=Huishoudelijk
id=2        name=Vervoermiddel
id=3        name=Sportartikel
We gaan het nu zo maken dat de gebruiker een lijstje krijgt van namen. Als de gebruiker er een vast kiest dan zal bijbehorende id worden opgeslagen,
Controller
Om dat lijstje op het scherm ter zetten, hebben we wel dat lijstje nodig en moet dat worden doorgegeven aan de view.
use AppModelsCategory;
Eerst moeten we het Category model bekend maken in de ProductController. Dan kunnen we alle categorieën lezen.
$categories = Category::all();
We laden alle beschikbare rijen uit de categories tabel en zetten die in het $categories object.
return view('product.form', compact('product','categories'));
Deze lijst geven we dan door aan de view.
View - stap1
We gaan nieuwe code toevoegen waarin de gebruiker kan kiezen. Dat is een heel bouw werk dat uit verschillende delen bestaat.
<label for="category_id">Categorie:</label>
<select name="category_id">
    <option value="1">Huishoudelijk</option>
    <option value="2">Vervoermiddel</option>
    <option value="3">Sportartikel</option>
</select>
Bovenin een label regel om aan te geven waar het over gaat. Dan het openen van de SELECT tag, die doorloopt tot onderin. In de SELECT tag geven we de naam op het item, zodat we die kunnen lezen en opslaan.
Dit is recht toe, recht aan code waarin de herhaling in de options regels opvalt. Links de waarde voor de id en rechts de name van de categorie.
View - stap2
In de controller hebben we eerder de lijst met controllers gelezen. En die is ook mooi ingedeeld met een id en een name.
We kunnen natuurlijk de waarden hard coded opnemen als in stap1, maar liever willen we natuurlijk gewoon de waarde uit de database tonen. Daarvoor gaan we door de lijst met producten leven en de huidige categorie stoppen we in de variabel $category.
foreach($categories as $category)
endforeach
En dan gaan we voor iedere categorie de regel aanpassen. We hadden hierboven al gezien hoe een Option regel eruit ziet. De bovenste regel is hier de oude regel met de hard coded gegevens. De regel eronder wat het gaat worden.
<option value="
2
">
Vervoermiddel
</option>
<option value="
{{ $category->id }}
">
{{ $category->name }}
</option>
We vervangen hier eerst de oranje id (6) waarde door de Blade directive voor de $category->id inclusief de accolades. Deze hebben we in de controller gelezen.
En hetzelfde voor de waarde "Vervoermiddel", welke we vervangen door $category->name, ook weer met de accolades.
View - stap3
We waren mooi gestructureerd aan het werk, maar moeten het nu wat rommeliger aan gaan doen. Lees het een paar keer door en probeer het te begrijpen. Als je het ooit zelf gaat bouwen, pak dan hierop terug.
Als we een product gaan wijzigen dan willen we dat de oude waarde ingevuld staat en niet steeds opnieuw hoeft te worden geselecteerd, ook als die niet wijzigt. Als we dit niet doen dan zal de select lijst iedere keer het bovenste item tonen (en niet het geselecteerde item).
We nemen weer het oude item:
<option value="{{ $category->id }}">{{ $category->name }}</option>
En pal vóór het groter-dan teken (>) in het midden gaan we onderstaande rode data toevoegen.
<option value="{{ $category->id }}" 
{{ old('category_id', $product->category_id) == $category->id ? 'selected' : '' }}
>{{ $category->name }}</option>
Voor de duidelijkheid hier even los
{{ old('category_id', $product->category_id) == $category->id ? 'selected' : '' }}
Om het lastig te maken bestaat deze code ook weer uit twee delen. In het eerste deel herkennen we de $product_category->id, dat is de huidige opgeslagen waarde. Verder op de regel $category_id is de waarde bij een eventuele validatie.
old('category_id', $product->category_id)
Dan komt het rechterdeel van het statement.
== $category->id ? 'selected' : ''
Hier vergelijken we de huidige opgeslagen waarde met het id nummer van de $category (vanuit de loop), als die gelijk zijn (het is dus een match), dan voegen we het HTML woord selected toe, anders doen we niets. Met de waarde er links voor is dit een if then else statement op een enkele regel.
Hieronder de gehele code bijeen voor het SELECT item..
<label for="category_id">Categorie:</label>
<select name="category_id" id="category_id">
    foreach($categories as $category)
        <option value="{{ $category->id }}" {{ old('category_id', $product->category->id) == $category->id ? 'selected' : '' }}>{{ $category->name }}</option>
    endforeach
</select>
Oefening
Het bouwen van de CRUD voor de categories tabel is niet in detail opgenomen. Als je nu een oefening wilt, dan adviseer ik je om die nu als eerste te gaan maken.