Week 5 · Arrays & strings

Productcatalogus: voordat je begint

  1. Open index.html en 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-az en #sort-za: de twee sorteerknoppen
  2. Bekijk de array products. Let op: dit zijn gewoon strings (tekst), geen objecten. Eén product is dus bijvoorbeeld 'Laptop Pro'.

  3. Open de console met F12 (Mac: Cmd + Option + J). Laat die de hele opdracht open staan.

Hoe hangt alles samen?

Zoekbalk / knoppenVeranderen searchTerm of sorting, en roepen filterProducts() aan
→
filterProducts()Maakt de lijst: eerst filteren op searchTerm, dan sorteren op sorting
→
showProducts(list)Maakt van elk product in de lijst een kaartje en zet de teller

Omdat searchTerm en sorting allebei bewaard blijven, en filterProducts() ze elke keer allebei gebruikt, werken zoeken en sorteren straks vanzelf tegelijk.

Week 5 · Stap 1

Producten tonen

Dit staat in je script.js
const showProducts = (list) => {
  // Toon elke productnaam als een <article> in #products
  // Laat in #counter de hoeveelheid producten zien
};

Zo maak je daar code van:

  1. Zet eerst bovenaan in de functie filterProducts() tijdelijk deze regel:

    const filtered = products;

    Waarom? Onderaan filterProducts staat al showProducts(filtered), maar filtered bestaat nog niet. Zonder deze regel krijg je de fout filtered is not defined en zie je niks. In stap 2 vervang je deze regel door het echte filter.

  2. 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?

  3. Maak een verwijzing naar #products en sla die op in een variabele, bijvoorbeeld container. Doe hetzelfde voor #counter, bijvoorbeeld in counter.

    const container = document.querySelector('#___');
    const counter = document.querySelector('#___');
  4. Maak de container leeg (nog steeds boven de loop).

    container.innerHTML = '';

    Waarom? Straks roep je showProducts bij elke letter die je typt opnieuw aan. Zonder deze regel komen de kaartjes er steeds bij.

  5. Maak een for...of loop door list. Noem één item in de loop product.

    for (const product of ___) {
    
    }

    Loop door list (de parameter), niet door products. Straks krijgt showProducts een gefilterde lijst, en die wil je tonen.

    ✔ Test: console.log(product) in de loop. Zie je 12 losse namen?

  6. Voeg in de loop met += een <article> toe aan de container, met de productnaam erin.

    container.innerHTML += `
      <article>
        <h3>${___}</h3>
      </article>
    `;

    product is al een string, dus je hebt geen destructuring of .name nodig. De variabele zelf is de naam.

  7. 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, niet products.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; in filterProducts).
  • undefined op je kaartje: je gebruikt product.name, maar een product is een string, geen object. Gebruik gewoon product.
  • 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 null in de console: het id in je querySelector klopt niet. Vergeet de # niet.
Week 5 · Stap 2

Zoekbalk

Eerst maak je het filter in filterProducts, daarna de event listener op de zoekbalk.

A. Filteren in filterProducts

Dit staat in je script.js
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:

  1. Vervang de tijdelijke regel const filtered = products; uit stap 1 door een .filter() op products.

    const filtered = products.filter(product => ___);

    .filter() loopt zelf door alle producten. Op de plek van ___ komt een check die true (product blijft) of false (product valt af) oplevert.

  2. Maak de check: zet product om naar kleine letters met .toLowerCase(), en kijk dan met .includes() of searchTerm erin zit.

    product.___().___(searchTerm)

    Waarom toLowerCase()? includes() let op hoofdletters: 'Laptop Pro'.includes('laptop') is false. 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

Dit staat in je script.js
// 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:

  1. Maak een verwijzing naar #search-bar en voeg een input event listener toe. Zet e tussen de haakjes van de functie.

    document.querySelector('#___').addEventListener('input', (e) => {
    
    });

    Waarom input en niet click? Het input event gaat af bij elke letter die je typt. Zo filter je live.

  2. Lees in de listener uit wat er in de zoekbalk staat met e.target.value.

    e.target is het element waarop het event gebeurde (de zoekbalk), en .value is wat erin getypt is.

    ✔ Test: console.log(e.target.value) en typ iets. Zie je bij elke letter een nieuwe log?

  3. Sla die waarde, omgezet naar kleine letters, op in de variabele searchTerm.

    searchTerm = e.target.value.___();

    Geen let ervoor: de variabele bestaat al bovenaan, je geeft hem alleen een nieuwe waarde.

  4. 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 bij product én bij searchTerm.
  • Cannot read properties of undefined (reading 'toLowerCase'): je gebruikt product.name. Een product is een string, gebruik gewoon product.
  • De lijst verandert niet tijdens typen: roep je filterProducts() aan in de listener? En gebruik je 'input' als event?
  • Assignment to constant variable: bovenaan moet let searchTerm staan, niet const.
Week 5 · Stap 3

Sorteren

Eerst maak je het sorteren in filterProducts, daarna de twee knoppen.

A. Sorteren in filterProducts

Dit staat in je script.js
  // 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:

  1. Maak onder je filtered-regel en boven showProducts(filtered) een if / else if op de variabele sorting.

    if (sorting === 'az') {
    
    } else if (sorting === ___) {
    
    }

    Waarom else if en geen else? Als sorting nog leeg is (''), wil je helemaal niet sorteren.

  2. Sorteer in de eerste if de array filtered met .sort().

    filtered.sort();
  3. Sorteer in de else if de array filtered eerst 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: na filtered.sort() is filtered gesorteerd.

Omdat je filtered sorteert (en niet products), blijft de originele array onaangetast.

B. De twee knoppen

Dit staat in je script.js
// 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:

  1. Maak een verwijzing naar #sort-az en voeg een click event listener toe.

    document.querySelector('#___').addEventListener('click', () => {
    
    });

    ✔ Test: zet console.log('klik') in de listener en klik op de knop.

  2. Zet in de listener de variabele sorting op 'az'.

  3. Roep daarna in de listener filterProducts() aan.

  4. Doe stap 1 t/m 3 nog een keer voor de knop #sort-za, maar zet sorting nu 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 in filterProducts, dan gebeurt het bij elke update.
  • Assignment to constant variable: je schrijft filtered = filtered.sort(). Dat hoeft niet, filtered.sort() is genoeg.
  • Er gebeurt niks na de klik: staat de if wel boven showProducts(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.

  1. Staat er iets roods in de console? Lees de eerste regel en zoek hem op bij Foutmeldingen.
  2. Geen fout, maar het doet niks? Zet console.log() op meerdere plekken. Waar stoppen de logs? Daar zit het probleem.
  3. Leg je code hardop uit, regel voor regel, aan een klasgenoot (of aan een badeendje). Vaak hoor je jezelf dan zeggen waar het misgaat.
  4. Zoek de term op in de zoekbalk van de cheat sheet.
  5. Vraag hulp en vertel daarbij: wat je wilde, wat je deed, en wat er gebeurde (met de foutmelding erbij).