Esme's Wiki - Lawlzilla7/ProjectTech-Team2 GitHub Wiki

Specialisatie - Backend

Aangezien alles niet lukte heb ik besloten opnieuw te beginnen en alles rustiger en uitgebreider te doen. Door het te herhalen en rustiger te doen is het uiteindelijk beter gelukt de server te bouwen en ermee te werken.

Week 1

Herhalen en JSON

Competentie: Oriënteren en begrijpen


In de eerste week hebben we voornamelijk JavaScript herhaald en opgefrist. Dit ging erg goed en de kennis was er nog wel. Deze week hebben we ook kennis gemaakt met JSON.

JSON

Competentie: Oriënteren en begrijpen


JSON wordt vaak gebruikt bij het uitwisselen van gegevens tussen een server en een webapplicatie. API's (Application Programming Interfaces) sturen vaak gegevens terug in JSON-formaat, en ontwikkelaars kunnen deze gegevens eenvoudig omzetten naar JavaScript-objecten.


Competentie: Verbeelden en conceptualiseren


In JavaScript kan een JSON-string worden omgezet naar een JavaScript-object met JSON.parse(). Omgekeerd kan een JavaScript-object worden omgezet naar een JSON-string met JSON.stringify().

// JSON naar JavaScript-object
const jsonString = '{"naam": "John", "leeftijd": 25}';
const javascriptObject = JSON.parse(jsonString);

// JavaScript-object naar JSON
const userObject = { naam: "Alice", leeftijd: 30 };
const jsonStringFromObject = JSON.stringify(userObject);

Daarnaast hebben we eerste opdrachten gemaakt om een asynchrone functie op te halen met Fetch.

Week 2

Installeren en testen

Tabbed Postman We zijn begonnen met node.js en NVM installeren. Daarna zijn we begonnen met het leren kennen van een API. Hierbij hebben we gebruik gemaakt van de Chrome extensie 'tabbed postman'. Met deze extensie ben ik aan de slag gegaan en heb ik een aantal requests gedaan, in dit geval GET en PATCH. Hierbij heb ik de [tutorial](https://www.youtube.com/watch?v=MpDuQBQfJZM) van Ivo gevolgd. tabbedpostman
Templating Engine ### Templating Engine Ik heb voor het eerst kennis gemaakt met EJS. Hierbij heb ik een aantal routes en views aangemaakt en heb ik de basis gemaakt voor het project. basisopzet aboutejs

Ik heb al een kleine basis met Svelte, waardoor ik dit wel snel begreep. Door

<head>
  <%- include('../partials/head'); %>
</head>
<body class="container"> 

toe te voegen hoef je straks bij eventuele aanpassingen deze alleen maar te doen op de 'head.ejs' in je partials, waardoor je dit dus niet bij 20 pagina's 20x hoeft aan te passen.

Week 4

API bouwen Nu ik alle theorie redelijk begrijp ben ik begonnen met het maken van de API. De frontenders zijn al best een eind met het ontwerp. Dat in combinatie met mijn eigen kennis willen verbreden, heb ik ervoor gekozen om de API zelf te bouwen. Hiervoor heb ik in MongoDB een database aangemaakt met verschillende collections. De collections heb ik opgedeeld in de verschillende types, SUV, Hatchback en Comfort. database api-suv

Voor elk type wil ik er 18 uitwerken, zodat er in ieder geval meerder opties naar boven komen bij het filteren door een gebruiker.

API in de database De API is af. Van verschillende auto's (merken) zijn er nu verschillende eigenschappen in de API. Iedere auto heeft 10 specificaties waar straks op gezocht en gefilterd kan worden. Zie het voorbeeld van 1 auto hieronder:
    {
        "prijs": 30000,
        "merk": "Citroen",
        "type": "personenauto",
        "brandstof": "benzine",
        "Bouwjaar": 2019,
        "kilometers": 15000,
        "kleur": "rood",
        "carrosserie": "hatchback",
        "velgen": "sport",
        "afbeelding":"/citroen-2019-hatchback-rod"
    },

Hiervan heb ik er dus een aantal uitgewerkt.

Filteren ## De basis van het filteren

Voor het filteren heb ik nieuwe code geschreven. In de URL kun je nu filteren. Je kunt dus in de URL nu zoeken naar bepaalde specificaties, de specificaties die je invult geven vervolgens het passende resultaat. Als je onderstaande opbouw gebruikt kun je dus nu verschillende auto's filteren.

            return { [value]: req.protocol + '://' + req.get('host') + `/api/auto?${req.params.veldnaam}=${value}` }

Filteren werkend maken

Om het filteren werkend te maken in onze applicatie is het nu van belang om het filteren te koppelen aan de knoppen die ingedrukt worden door de gebruiker.

Afbeeldingen Ik heb voor alle auto's een waarde 'afbeelding' aangemaakt en deze een naam gegeven. Nu heb ik allemaal afbeeldingen opgeslagen. Het volgende punt is dus om de afbeelding te laten tonen als je filtert op bepaalde eigenschappen.

Week 5

Sorteren Om de filteren heb ik nu alles goed staan. Ik ga nu het sorteren toevoegen. Ik heb code toegevoegd om te sorteren doormiddel van de 'sort' functie van MongoDB. Ik heb hiervoor deze code toegevoegd:
    let sorteren = {};
    if (req.query.sort) {
        const sorteerVeld = req.query.sort.startsWith('-') ? req.query.sort.slice(1) : req.query.sort;
        const sorteerVolgorde = req.query.sort.startsWith('-') ? -1 : 1;
        sorteren[sorteerVeld] = sorteerVolgorde;
        delete req.query.sort;
    }

Waarbij - betekent dat je aflopend zoekt, en zonder - zoek je op oplopend. Als ik vervolgens in de zoekbalk (hetzelfde als met filteren) zoek op http://localhost:8000/api/auto?sort=prijs, krijg ik geen resultaten. Dit werkt dus nog niet helemaal.

Ik open de API in Tabbed Postman zodat ik makkelijk mijn resultaat te zien krijg. Ook hier werkt het filteren nog steeds goed. In Tabbed Postman krijg ik geen resultaat te zien als ik sort=prijs doe.

Scherm­afbeelding 2024-03-28 om 10 08 05
Volledige lijst API Ik wil eerst de volledige lijst naar voren krijgen inclusief afbeeldingen. Met deze code:
<main>
    <h2> Autos:</h2>
    <% if(auto[0]){
        for (auto of auto) { %>
            <ul> 
                <li>
                    <%= auto.merk %> 
                    <%= auto.afbeelding %>
                </li>
            </ul>
        <% } %>
               
    <% } else {%>  
        <p>No auto found &#128531;</p>
    <% } %>
</main>

Kreeg ik dit resultaat. Hij pakt dus wel de informatie uit de API maar de afbeelding laadt nog niet.

Scherm­afbeelding 2024-03-28 om 12 03 04

Toen heb ik de code aangepast naar dit:

    <h2> Autos:</h2>
    <% if(auto[0]){
        for (auto of auto) { %>
            <ul> 
                <li>
                    <%= auto.merk %> 
                    < - img src="./images/auto/<%= auto.afbeelding %>">
                </li>
                
            </ul>
        <% } %>
               
    <% } else {%>  
        <p>No auto found &#128531;</p>
    <% } %>

Waarbij ik dit als resultaat kreeg:

Scherm­afbeelding 2024-03-28 om 11 59 35

Het lijkt erop dat het pad nog niet helemaal klopt naar de afbeeldingen waardoor ze niet geladen worden.

Deze melding is te zien in de terminal waarbij ik er dus achter kwam dat het pad niet leek te kloppen.

Scherm­afbeelding 2024-03-28 om 12 07 27

Uiteindelijk bleek dat alle plaatjes opgeslagen waren als .jpeg maar dat niet in de padnaam stond. Stom probleem maar gelukkig wel opgelost nu. Ik krijg nu de namen en de afbeeldingen te zien. Nu moet ik dus nog alle andere eigenschappen toevoegen zodat dit ook te zien is in de resultaten.

Scherm­afbeelding 2024-03-28 om 14 12 13
Samenvoegen met Frontend Furkan Bij het samenvoegen lijkt de CSS niet ingeladen te worden. Scherm­afbeelding 2024-03-28 om 16 10 45

Ik heb wel dezelfde inhoud van de

gebruikt als in results.html. Als ik de verander van naar werkt het wel en krijg ik de juiste opmaak te zien. Voor deze pagina heb ik (tijdelijk) een nieuwe partial aangemaakt 'header-resultaten.ejs' die ik invoeg door middel van
header
    <%- include('../partials/header-resultaten'); %> 
/header

Het volgende probleem waar ik tegenaan loop is het bereiken van de resultaten pagina. De knop Opslaan Leidt namelijk nergens heen en ook de functie kan ik niet vinden.

Ik heb daarom een functie aangemaakt en de button aangepast naar

<button class="OpslaanKnop" onclick="navigateToResults()">Opslaan</button>
function navigateToResults() {
    window.location.href = '/resultaten'; // Navigeer naar de 'results' pagina
}
Resultaten laden Op de build pagina kiest de gebruiker verschillende opties, namelijk: velgen, body en kleur. Deze gekozen gegevens moeten worden doorgegeven aan de resultaten pagina om op die manier de juiste zoek resultaten te geven.

Hiervoor maak ik een asynchrone functie aan in script.js. Met Fetch wil ik gegevens van de server ophalen en verzenden. De gegevens worden gehaald uit de API. Eerder had ik door te zoeken in de search bar geregeld dat je de juiste filter resultaten krijgt, bijvoorbeeld door http://localhost:8000/api/auto/?velgen=sport&kleur=blauw&carrosserie=coupe in te voeren. Dus met (fetch(/api/auto/${window.location.search}) worden de resultaten waarop de gebruiker geselecteerd heeft opgehaald. window.location is een object dat informatie bevat over de huidige URL van de browser, dus die wordt opgehaald.

Ik heb een foutmelding ingesteld voor als de zoekresultaten niet werken, als het wel werkt worden de resultaten opgehaald uit de Json.

       .then(result => {
            if (!result.ok) {
                alert('Helaas ging er iets mis bij het ophalen van het resultaat. Probeer het later nogmaals.')
            } else {
                return result.json()
            }
        })

Nog een foutmelding voor als de zoekresultaten niet kloppen.

if (autos.length === 0) {
                alert('Er zijn geen auto\'s gevonden die aan je zoekcriteria voldoen. Probeer het met andere zoekcriteria.')

In Furkan zijn HTML wordt de code getoond door middel van een ul met class 'searchResult':

Dus in mijn functie wil ik de zoekresultaten uit de API sturen naar de li 'searchResult'.

                const searchResult = document.querySelector('ul.SearchResultList')

met .createElement maakt de javaScript iedere keer een nieuw list item toe. Vervolgens worden de volgende gegevens weergegeven: brandstof, bouwjaar en km stand van de gekozen opties. li.style.backgroundImage = url(/images/auto/${auto.afbeelding}) li.appendChild(document.createElement('h3')).textContent = auto.merk li.appendChild(document.createElement('p')).textContent = Brandstof: ${auto.brandstof} li.appendChild(document.createElement('p')).textContent = Bouwjaar: ${auto.Bouwjaar} li.appendChild(document.createElement('p')).textContent = KM Stand: ${auto.kilometers}

Als je nu in de URL http://localhost:8000/results?kleur=groen zoekt. Krijg je alle groene auto's, inclusief de bovenstaande waarden.

Scherm­afbeelding 2024-04-02 om 19 24 29

Week 6

Detailpagina De detailpagina is gemaakt met statische html maar moet uiteindelijk dynamisch zijn. Met EJS ga ik dit doen. De resultaten worden nu geladen naar de resultaten pagina. Als je op zo'n resultaat klikt wil je dan vervolgens dat de detailpagina de informatie toont passend bij het resultaat. Deze data ga ik dus weer ophalen uit de database.

poging 1

Ik probeer het eerst op dezelfde manier als de resultaten pagina. Dus ik maak een functie die gegevens ophaalt (fetch) uit de api om daar vervolgens iets mee te doen.

detailpagina - resultaten laten zien
function showDetails() {
    fetch(`/api/auto/${window.location.search}`)
        .then(result => {
            if (!result.ok) {
                alert('Deze auto is helaas niet beschikbaar, kies een andere auto.')
            } else {
                return result.json()
            }
        })
        .then(autos => {
            if (autos.length === 0) {
                alert('Deze auto is helaas niet beschikbaar, kies een andere auto.')
            } else {
                // auto's renderen:
                const detailResult = document.querySelector('ul.detailResultsList')
                detailResult.innerHTML = ''
            }
        })
}

Het verschil is dat je nu geen list items toevoegt, maar p's en h2's wil aanpassen. Door logisch na te denken bedenk ik dus dat dit moet met EJS, dat ga ik dus eerst even doen. Ik zet de statische html om in dynamische EJS.

                        <h2 class="car-name"><%= auto.merk %></h2>
                                <p><%= auto.carrosserie %></p>
                                <p><%= auto.brandstof %></p>
                                <p><%= auto.kilometers.toLocaleString() %> km</p>
                    <p>€ <%= auto.prijs.toLocaleString() %>,-</p>

Met .toLocaleString zullen de getallen netjes met een . worden weergegeven (bron: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString) - klein detail, wel leuk!

Vervolgens heb ik gekeken naar feedback. Want als er geen auto's zijn, of de auto is er niet meer moet er ook geen detailpagina komen. Ik heb een if else statement toegevoegd in mijn detail.ejs om dit te realiseren.

           <% if(!auto){ %>
                <div class="detail-background">
                <h2>Auto niet gevonden</h2>
                <p>Ga naar <a href="/results">het overzicht</a> om alle auto's te bekijken.</p>
                </div>
            <% } else{ %> 

Waarbij binnen else dus de omgezette code staat die getoond moet worden als alles goed gaat.

De basis staat nu. Nu moet ik zorgen dat de juiste auto getoond wordt. De auto's hebben in mongodb allemaal een Id gekregen. Als ik die ID meegeef als je klikt op het resultaat, moet ik dus met ejs de juiste informatie kunnen ophalen uit de api en invullen in de html.

Dit ga ik uiteraard doen in server.js. In de functie voer ik een HTTP request uit voor de passende id. Met behulp van de findOne()-methode wordt een enkel document uit de database gezocht dat overeenkomt met de opgegeven _id. Dit document wordt vervolgens opgeslagen in de variabele 'auto'.

Dit geeft het volgende resultaat:

Ik klik op deze auto:

Scherm­afbeelding 2024-04-02 om 20 30 16

En dit is het resultaat:

Scherm­afbeelding 2024-04-02 om 20 30 50

Waarbij de aangegeven specs uit de API komen en worden getoond.

Week 7

Favorieten toevoegen Het moeilijkste stuk moet ik nog doen. Dit is het toevoegen van favorieten. Het volgende is wat er moet gebeuren: er moet een item zijn dat je kunt toevoegen aan favorieten. Dit item moet je alleen kunnen opslaan als je ingelogd bent, het moet namelijk gekoppeld worden aan je account.

Ik maak een asynchrone functie onBookmark aan. Hierin wil ik eerst zorgen dat de gebruiker ingelogd is. Kijkende naar de code van Sindy, moet ik hiervoor een sessie hebben. Met if (!req.session.username) controleer ik of de gebruiker is ingelogd. Indien de gebruiker niet ingelogd is, wordt deze doorgestuurd naar login door return res.redirect('/login').

Foutje! Waar ik in de start van de functie if (!req.session.username) heb toegevoegd. Blijkt nu dat dit niet genoeg is. Als ik namelijk een ID invoer die niet bestaat dan krijg ik niet het juiste resultaat. Daarom voeg ik if (!req.body.carId)) toe, zodat ook dit gecontroleerd wordt.

Door _id = new ObjectId(req.body.carId + '') wordt een nieuwe Objectid aangemaakt die gekoppeld wordt aan de id van de gebruiker zodat de favoriet toegevoegd wordt aan het account.

Met deleteOne zorg ik ervoor dat de favoriet verwijderd kan worden en met InsertOne voeg ik favorieten toe.

Pagina's samenvoegen De opmaak van de resultaten pagina en de favorieten pagina zijn eigenlijk hetzelfde, alleen moet bij favorieten een 'verwijder' optie toegevoegd worden. Ik wil dus deze pagina's eigenlijk hetzelfde hebben want waarom zou je twee pagina's hebben voor iets wat vrijwel hetzelfde is. Met EJS kun je dit namelijk heel makkelijk doen, omdat je een titel bijvoorbeeld dynamisch kan maken.

met de functie onBookmark ga ik dus results.ejs renderen. Door de knop 'voeg toe aan favorieten' wel te laten leiden naar /bookmark met app.get('/bookmark', onBookmark) . in de functie onBookmark zeg ik vervolgens

res.render('pages/results', {autos, title: "Favorieten", mode: 'favorites'})

waarbij ik in het ejs bestand de titel en mode aanpas zodat dit kloppend is bij de pagina. En voor resultaten

app.get('/results', filteredresults)
app.get('/results', filteredresults)

async function filteredresults(req, res) {
	const database = client.db('autolijst');
    const collection = database.collection('auto');
	const autos = await collection.find(req.query).toArray()
	res.render('pages/results', {autos, title: "Resultaten", mode: 'results'})
}

waarbij ik hier dus meegeef dat de titel resultaten moet zijn en de mode results. Voor de opslag van de complete site is dit dus prettig, want in plaats van dat er nog een complete pagina opgeslagen moet worden, is dit compact op één pagina en veranderen alleen wat kleine elementen zoals een titel.

Competenties

Compenties Voor het volledige beslag van de competenties die ik heb toegepast in dit project kun u mijn competentieverslag lezen, maar voor de volledigheid wilde ik het hier ook in verwerken.

Oriënteren en Begrijpen We hebben in de oriëntatiefase verschillende mogelijke concepten bedacht waarmee we allemaal naar mogelijke uitwerkingen hebben gekeken.

Verbeelden en Conceptualiseren We hebben verschillende job stories opgesteld, waarbij ik gekeken heb naar passende oplossingen om de gebruiker zo goed mogelijk te ondersteunen.

Prototypen en uitwerken In het concept heb ik onderbouwde principes, conventies en best-practices op het gebied van vormgeving, interactie en techniek toegepast Gebruiksvriendelijkheid (Usability), Efficiënte interactie, Gebruik van Frameworks en Libraries, Gegevensbeheer met Databases.

Evalueren Tijdens de feedback sessies ben ik continu bezig geweest met het bijhouden van de ontvangen feedback. Ik heb op deze momenten voornamelijk planning gerichte feedback gekregen, voornamelijk in teamverband

Samen ontwerpen Ik heb de officiële feedback momenten vastgelegd en doorgegeven aan de groep wat we ermee moeten. Ook zorgde ik dat alles up to date was vóór de feedback momenten.

Bronnen

Bronnen routing -> https://developer.mozilla.org/en-US/docs/Learn/Server-side/Express_Nodejs/routes .parse -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/parse https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/JSON/stringify https://developer.mozilla.org/en-US/docs/Web/API/URLSearchParams https://developer.mozilla.org/en-US/docs/Web/API/Window/alert https://developer.mozilla.org/en-US/docs/Web/API/Document/createElement .length -> https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments/length https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toLocaleString https://stackoverflow.com/questions/8216918/can-i-use-conditional-statements-with-ejs-templates-in-jmvc https://www.geeksforgeeks.org/express-js-res-redirect-function/ https://expressjs.com/en/resources/middleware/session.html https://www.mongodb.com/docs/manual/reference/method/ObjectId/ https://www.mongodb.com/docs/manual/reference/method/db.collection.insertOne/ https://www.mongodb.com/docs/manual/reference/method/db.collection.deleteOne/
⚠️ **GitHub.com Fallback** ⚠️