Productcatalogus: voordat je begint
-
Open
index.htmlen zoek deze id's op. Die heb je in je JavaScript nodig:#products: hier komen de kaartjes#counter: hier komt het aantal producten#search-bar: de zoekbalk#sort-azen#sort-za: de twee sorteerknoppen
-
Bekijk de array
products. Let op: dit zijn gewoon strings (tekst), geen objecten. Eén product is dus bijvoorbeeld'Laptop Pro'. -
Open de console met
F12(Mac:Cmd + Option + J). Laat die de hele opdracht open staan.
Hoe hangt alles samen?
searchTerm of sorting, en roepen filterProducts() aansearchTerm, dan sorteren op sortingOmdat searchTerm en sorting allebei bewaard blijven, en filterProducts() ze elke keer allebei gebruikt, werken zoeken en sorteren straks vanzelf tegelijk.
Producten tonen
const showProducts = (list) => {
// Toon elke productnaam als een <article> in #products
// Laat in #counter de hoeveelheid producten zien
};
Zo maak je daar code van:
-
Zet eerst bovenaan in de functie
filterProducts()tijdelijk deze regel:const filtered = products;Waarom? Onderaan
filterProductsstaat alshowProducts(filtered), maarfilteredbestaat nog niet. Zonder deze regel krijg je de foutfiltered is not defineden zie je niks. In stap 2 vervang je deze regel door het echte filter. -
Ga naar de functie
showProducts(list). Alle code van stap 1 schrijf je binnen deze functie, onder de comments.✔ Test: zet
console.log(list)in de functie. Zie je een array met 12 productnamen? -
Maak een verwijzing naar
#productsen sla die op in een variabele, bijvoorbeeldcontainer. Doe hetzelfde voor#counter, bijvoorbeeld incounter.const container = document.querySelector('#___'); const counter = document.querySelector('#___'); -
Maak de container leeg (nog steeds boven de loop).
container.innerHTML = '';Waarom? Straks roep je
showProductsbij elke letter die je typt opnieuw aan. Zonder deze regel komen de kaartjes er steeds bij. -
Maak een
for...ofloop doorlist. Noem één item in de loopproduct.for (const product of ___) { }Loop door
list(de parameter), niet doorproducts. Straks krijgtshowProductseen gefilterde lijst, en die wil je tonen.✔ Test:
console.log(product)in de loop. Zie je 12 losse namen? -
Voeg in de loop met
+=een<article>toe aan de container, met de productnaam erin.container.innerHTML += ` <article> <h3>${___}</h3> </article> `;productis al een string, dus je hebt geen destructuring of.namenodig. De variabele zelf is de naam. -
Zet onder de loop het aantal producten in de teller. Het aantal items in een array vind je met
.length.counter.textContent = `Aantal producten: ${___.length}`;Gebruik
list.length, nietproducts.length. Anders staat er altijd 12, ook als je zoekt.
Waar staat wat?
Wat maar één keer hoeft, staat buiten de loop. Wat per product gebeurt, staat in de loop.
const showProducts = (list) => {
// stap 3: verwijzingen naar #products en #counter → 1 keer, boven de loop
// stap 4: container leegmaken → 1 keer, boven de loop
for (const product of list) {
// stap 6: <article> toevoegen → per product, in de loop
}
// stap 7: teller bijwerken → 1 keer, onder de loop
};
Klaar als: je 12 kaartjes ziet met een productnaam, en de teller "Aantal producten: 12" zegt.
Werkt het niet?
filtered is not defined: je bent stap 1 vergeten (const filtered = products;infilterProducts).undefinedop je kaartje: je gebruiktproduct.name, maar een product is een string, geen object. Gebruik gewoonproduct.- Teller blijft leeg: staat de teller-regel per ongeluk bóven de loop of in een andere functie? En klopt het id
#counter? - Fout met
nullin de console: het id in jequerySelectorklopt niet. Vergeet de#niet.
Zoekbalk
Eerst maak je het filter in filterProducts, daarna de event listener op de zoekbalk.
A. Filteren in filterProducts
const filterProducts = () => {
// Maak een variabele 'filtered' aan door de products array te filteren op searchTerm
// Gebruik hiervoor filter() en includes() en toLowerCase()
...
Zo maak je daar code van:
-
Vervang de tijdelijke regel
const filtered = products;uit stap 1 door een.filter()opproducts.const filtered = products.filter(product => ___);.filter()loopt zelf door alle producten. Op de plek van___komt een check dietrue(product blijft) offalse(product valt af) oplevert. -
Maak de check: zet
productom naar kleine letters met.toLowerCase(), en kijk dan met.includes()ofsearchTermerin zit.product.___().___(searchTerm)Waarom
toLowerCase()?includes()let op hoofdletters:'Laptop Pro'.includes('laptop')isfalse. Als je alles in kleine letters vergelijkt, maakt het niet uit wat de gebruiker typt.✔ Test: verander bovenaan tijdelijk
let searchTerm = 'mu'. Zie je alleen "Draadloze muis" en "Muismat XL"? Zet hem daarna terug op''.
Waarom zie je alles als searchTerm leeg is?
Elke tekst bevat een lege tekst: 'laptop pro'.includes('') is true. Daarom zie je bij het openen van de pagina gewoon alle producten. Daar hoef je dus niks extra's voor te doen.
B. De zoekbalk
// Maak een eventlistener voor de #search-bar input
// Sla de waarde op in de searchTerm variabele en roep filterProducts() aan
Zo maak je daar code van:
-
Maak een verwijzing naar
#search-baren voeg eeninputevent listener toe. Zetetussen de haakjes van de functie.document.querySelector('#___').addEventListener('input', (e) => { });Waarom
inputen nietclick? Hetinputevent gaat af bij elke letter die je typt. Zo filter je live. -
Lees in de listener uit wat er in de zoekbalk staat met
e.target.value.e.targetis het element waarop het event gebeurde (de zoekbalk), en.valueis wat erin getypt is.✔ Test:
console.log(e.target.value)en typ iets. Zie je bij elke letter een nieuwe log? -
Sla die waarde, omgezet naar kleine letters, op in de variabele
searchTerm.searchTerm = e.target.value.___();Geen
letervoor: de variabele bestaat al bovenaan, je geeft hem alleen een nieuwe waarde. -
Roep daarna in de listener
filterProducts()aan.
Klaar als: de lijst bij elke letter kleiner wordt, "MUIS" en "muis" hetzelfde resultaat geven, en de teller meeverandert.
Werkt het niet?
- Zoeken met een hoofdletter vindt niks: je bent
toLowerCase()aan één van de twee kanten vergeten. Het moet bijproductén bijsearchTerm. Cannot read properties of undefined (reading 'toLowerCase'): je gebruiktproduct.name. Een product is een string, gebruik gewoonproduct.- De lijst verandert niet tijdens typen: roep je
filterProducts()aan in de listener? En gebruik je'input'als event? Assignment to constant variable: bovenaan moetlet searchTermstaan, nietconst.
Sorteren
Eerst maak je het sorteren in filterProducts, daarna de twee knoppen.
A. Sorteren in filterProducts
// Sorteer hier op sorting:
// als sorting 'az' is, sorteer van A naar Z
// als sorting 'za' is, sorteer van Z naar A
showProducts(filtered);
};
Zo maak je daar code van:
-
Maak onder je
filtered-regel en bovenshowProducts(filtered)eenif / else ifop de variabelesorting.if (sorting === 'az') { } else if (sorting === ___) { }Waarom
else ifen geenelse? Alssortingnog leeg is (''), wil je helemaal niet sorteren. -
Sorteer in de eerste
ifde arrayfilteredmet.sort().filtered.sort(); -
Sorteer in de
else ifde arrayfilteredeerst met.sort()en draai hem daarna om met.reverse().filtered.___().___();✔ Test: verander bovenaan tijdelijk
let sorting = 'za'. Begint de lijst met "Webcam HD"? Zet hem daarna terug op''.
Let op: .sort() werkt anders dan .filter()
.filter()laat de oude array met rust en geeft een nieuwe array terug. Die moet je opvangen in een variabele (const filtered = ...)..sort()en.reverse()veranderen de array zelf. Je hoeft het resultaat dus niet op te vangen: nafiltered.sort()isfilteredgesorteerd.
Omdat je filtered sorteert (en niet products), blijft de originele array onaangetast.
B. De twee knoppen
// Maak een eventlistener voor de #sort-az button
// Zet sorting op 'az' en roep filterProducts() aan
// Maak een eventlistener voor de #sort-za button
// Zet sorting op 'za' en roep filterProducts() aan
Zo maak je daar code van:
-
Maak een verwijzing naar
#sort-azen voeg eenclickevent listener toe.document.querySelector('#___').addEventListener('click', () => { });✔ Test: zet
console.log('klik')in de listener en klik op de knop. -
Zet in de listener de variabele
sortingop'az'. -
Roep daarna in de listener
filterProducts()aan. -
Doe stap 1 t/m 3 nog een keer voor de knop
#sort-za, maar zetsortingnu op'za'.
Klaar als:
- "A-Z" de lijst van Bluetooth speaker tot Webcam HD zet, en "Z-A" andersom
- Zoeken en sorteren tegelijk werken: typ
mu, klik op Z-A, en je ziet Muismat XL boven Draadloze muis - De sortering blijft staan als je daarna verder typt
Werkt het niet?
- Sortering verdwijnt zodra je typt: je sorteert in de listener van de knop in plaats van in
filterProducts. Het sorteren moet infilterProducts, dan gebeurt het bij elke update. Assignment to constant variable: je schrijftfiltered = filtered.sort(). Dat hoeft niet,filtered.sort()is genoeg.- Er gebeurt niks na de klik: staat de
ifwel bovenshowProducts(filtered)? Anders toon je de lijst voordat hij gesorteerd is.
Nog steeds vast?
Loop dit lijstje af voordat je hulp vraagt. Vaak vind je het zelf, en anders kun je je vraag veel beter stellen.
- Staat er iets roods in de console? Lees de eerste regel en zoek hem op bij Foutmeldingen.
- Geen fout, maar het doet niks? Zet
console.log()op meerdere plekken. Waar stoppen de logs? Daar zit het probleem. - Leg je code hardop uit, regel voor regel, aan een klasgenoot (of aan een badeendje). Vaak hoor je jezelf dan zeggen waar het misgaat.
- Zoek de term op in de zoekbalk van de cheat sheet.
- Vraag hulp en vertel daarbij: wat je wilde, wat je deed, en wat er gebeurde (met de foutmelding erbij).