get-frontend/webshop_app/mvc-emne2/README-NO.md
2025-07-01 20:42:02 +02:00

15 KiB

MVC Nettbutikk Applikasjon

En ren JavaScript-implementering av en nettbutikk som bruker Model-View-Controller (MVC) arkitekturmønsteret. Dette utdanningsprosjektet demonstrerer kjerne webutviklingskonsepter uten eksterne rammeverk.

🏗️ Arkitekturoversikt

Denne applikasjonen følger MVC-mønsteret med et sentralisert view-renderingssystem:

  • Model: Håndterer databehandling og forretningslogikk
  • View: Administrerer HTML-generering og DOM-manipulering
  • Controller: Koordinerer brukerinteraksjoner og dataflyt

📊 UML Diagrammer

Klassediagram

classDiagram
    class Model {
        -products: Array~Product~
        -cart: Array~CartItem~
        +getAllProducts() Array~Product~
        +getProductById(id) Product
        +addToCart(productId, quantity) boolean
        +removeFromCart(productId) void
        +updateCartQuantity(productId, quantity) void
        +getCart() Array~CartItem~
        +getCartTotal() number
        +getCartItemCount() number
        +clearCart() void
        +saveCartToStorage() void
        +loadCartFromStorage() Array~CartItem~
        +initializeCart() void
    }
    
    class View {
        -currentPage: string
        -cartCount: number
        +updateView(viewType, data) void
        +generateNavbar() string
        +generateProductsPage(products) string
        +generateProductDetailPage(product) string
        +generateCartPage(cartItems, total, itemCount) string
        +createProductCard(product) string
        +createCartItem(item) string
        +attachEventListeners() void
        +updateCartCountInNav() void
        +showNotification(message) void
    }
    
    class Controller {
        +loadProducts() void
        +showProductDetail(productId) void
        +handleAddToCart(productId) void
        +handleRemoveFromCart(productId) void
        +changeQuantity(productId, change) void
        +handleClearCart() void
        +navigateToProducts() void
        +navigateToCart() void
        +updateCartDisplay() void
    }
    
    class Product {
        +id: number
        +name: string
        +price: number
        +description: string
        +image: string
        +category: string
    }
    
    class CartItem {
        +productId: number
        +quantity: number
        +product: Product
    }
    
    class App {
        +initialize() void
    }
    
    Controller --> Model : bruker
    Controller --> View : oppdaterer
    View --> Controller : sender hendelser
    Model --> Product : inneholder
    Model --> CartItem : administrerer
    CartItem --> Product : refererer til
    App --> Controller : initialiserer
    App --> Model : setter opp
    App --> View : starter

Sekvensdiagram - Legg til i handlekurv

sequenceDiagram
    participant U as Bruker
    participant V as View
    participant C as Controller
    participant M as Model
    
    U->>V: Klikker "Legg i handlekurv"
    V->>C: handleAddToCart(productId)
    C->>M: addToCart(productId)
    M->>M: getProductById(productId)
    M->>M: Finn eksisterende element eller lag nytt
    M->>M: saveCartToStorage()
    M-->>C: return true/false
    
    alt Vellykket
        C->>M: getProductById(productId)
        M-->>C: return product
        C->>V: updateView('notification', {message})
        C->>C: updateCartDisplay()
        C->>M: getCart()
        M-->>C: return cart
        C->>M: getCartTotal()
        M-->>C: return total
        C->>M: getCartItemCount()
        M-->>C: return itemCount
        C->>V: updateView('cart', {cartItems, total, itemCount})
        C->>V: updateView('cart-count', {count})
        V->>V: generateCartPage() eller updateCartCountInNav()
        V-->>U: Oppdatert UI med notifikasjon
    else Feilet
        C->>V: updateView('notification', {message: 'Feil'})
        V-->>U: Feilmelding
    end

📁 Prosjektstruktur

mvc-emne2/
├── index.html          # Hoved HTML-fil med enkelt app-container
├── styles.css          # Applikasjonsstyling
├── js/
│   ├── app.js          # Applikasjonsinitialisering
│   ├── model.js        # Datalag og forretningslogikk
│   ├── view.js         # UI-rendering og HTML-generering
│   └── controller.js   # Brukerinteraksjonshåndtering
├── flow-diagram.md     # Applikasjonsflytvisualisering
├── README.md          # Engelsk dokumentasjon
├── README-NO.md       # Norsk dokumentasjon (denne filen)
└── ACCESSIBILITY.md   # Tilgjengelighetsdokumentasjon

🔧 Nøkkelkomponenter

1. Model (model.js)

Formål: Administrerer applikasjonsdata og persistering

Nøkkelfunksjoner:

  • getAllProducts() - Returnerer produktkatalog
  • getProductById(id) - Henter spesifikt produkt
  • addToCart(productId, quantity) - Legger til varer i handlekurv
  • removeFromCart(productId) - Fjerner varer fra handlekurv
  • updateCartQuantity(productId, quantity) - Oppdaterer vareantall
  • getCart() - Returnerer gjeldende handlekurvinnhold
  • getCartTotal() - Beregner total handlekurvpris
  • getCartItemCount() - Returnerer totalt antall varer
  • clearCart() - Tømmer handlekurven
  • saveCartToStorage() / loadCartFromStorage() - LocalStorage-persistering

Datastruktur:

// Produkt
{
    id: number,
    name: string,
    price: number,
    description: string,
    image: string (emoji),
    category: string
}

// Handlekurvvare
{
    productId: number,
    quantity: number,
    product: Product
}

2. View (view.js)

Formål: Håndterer all UI-rendering gjennom en sentralisert updateView-funksjon

Kjernearkitektur:

function updateView(viewType, data = {}) {
    switch (viewType) {
        case 'products': // Rendrer produktliste
        case 'product-detail': // Rendrer enkelt produkt
        case 'cart': // Rendrer handlekurv
        case 'cart-count': // Oppdater handlekurvmerke
        case 'notification': // Vis brukermeldinger
    }
}

Nøkkelfunksjoner:

  • Enkelt inngangspunkt: All rendering går gjennom updateView()
  • Komplett sidegenerering: Genererer hele side-HTML inkludert navigasjon
  • Event Listener-administrasjon: Fester automatisk event listeners etter hver rendering
  • Mallfunksjoner: Modulære HTML-genereringsfunksjoner

HTML-genereringsfunksjoner:

  • generateNavbar() - Lager navigasjonsheader
  • generateProductsPage(products) - Produktlisteside
  • generateProductDetailPage(product) - Produktdetaljside
  • generateCartPage(cartItems, total, itemCount) - Handlekurvside
  • createProductCard(product) - Individuelt produktkort
  • createCartItem(item) - Individuell handlekurvvare

3. Controller (controller.js)

Formål: Håndterer brukerinteraksjoner og koordinerer mellom Model og View

Navigasjonsfunksjoner:

  • navigateToProducts() - Viser produktliste
  • navigateToCart() - Viser handlekurv
  • showProductDetail(productId) - Viser produktdetaljer

Handlekurvadministrasjon:

  • handleAddToCart(productId) - Legger til produkt i handlekurv
  • handleRemoveFromCart(productId) - Fjerner produkt fra handlekurv
  • changeQuantity(productId, change) - Oppdaterer produktantall
  • handleClearCart() - Tømmer hele handlekurven
  • updateCartDisplay() - Oppdaterer handlekurvvisning og teller

Nøkkeldesignmønstre:

  • Alle funksjoner kaller updateView() for UI-oppdateringer
  • Brukernotifikasjoner håndteres konsistent
  • Handlekurvtilstand persisteres automatisk etter endringer

4. Applikasjonsinitialisering (app.js)

Formål: Bootstrapper applikasjonen

Initialiseringsflyt:

  1. Vent på at DOM skal laste
  2. Initialiser handlekurv fra localStorage
  3. Last produkter fra model
  4. Renderer initial produktside
  5. Oppdater handlekurvteller
document.addEventListener('DOMContentLoaded', function() {
    // Fjern lastingstilstand
    const loadingElement = document.querySelector('.loading');
    if (loadingElement) {
        loadingElement.remove();
    }
    
    initializeCart();
    
    const products = getAllProducts();
    const itemCount = getCartItemCount();
    
    updateView('products', { products });
    updateView('cart-count', { count: itemCount });
    
    console.log('Nettbutikk MVC Demo initialisert!');
});

🔄 Dataflyt

1. Applikasjonsoppstart

HTML-lasting → DOMContentLoaded → initializeCart() → loadCartFromStorage() → 
getAllProducts() → updateView('products') → generateProductsPage() → attachEventListeners()

2. Brukerinteraksjoner

Brukerklikk → Controller-funksjon → Model-operasjon → updateView() → 
HTML-generering → Event Listener-tilkobling → UI-oppdatering

3. Handlekurvoperasjoner

Legg til i handlekurv → addToCart() → saveCartToStorage() → updateCartDisplay() → 
updateView('cart') + updateView('cart-count') → showNotification()

🎨 View-renderingssystem

Sentralisert rendering

Alle UI-oppdateringer flyter gjennom den enkelte updateView()-funksjonen:

updateView('products', { products: [...] });
updateView('product-detail', { product: {...} });
updateView('cart', { cartItems: [...], total: 0, itemCount: 0 });
updateView('cart-count', { count: 0 });
updateView('notification', { message: 'Vellykket!' });

Komplett sidegenerering

I motsetning til tradisjonell DOM-manipulering genererer dette systemet komplett side-HTML:

function generateProductsPage(products) {
    return `
        ${generateNavbar()}
        <main>
            <section class="page active">
                <h2>Våre Produkter</h2>
                <div class="products-grid">
                    ${products.map(product => createProductCard(product)).join('')}
                </div>
            </section>
        </main>
    `;
}

Event Listener-administrasjon

Etter hver rendering festes event listeners på nytt:

function attachEventListeners() {
    const productsLink = document.querySelector('[data-page="products"]');
    const cartLink = document.querySelector('[data-page="cart"]');
    
    if (productsLink) {
        productsLink.addEventListener('click', function(e) {
            e.preventDefault();
            navigateToProducts();
        });
    }
    // ... flere listeners
}

💾 Datapersistering

LocalStorage-integrasjon

Handlekurvdata persisteres automatisk:

function saveCartToStorage() {
    try {
        localStorage.setItem('webstore_cart', JSON.stringify(cart));
    } catch (error) {
        console.error('Feil ved lagring av handlekurv til localStorage:', error);
    }
}

function loadCartFromStorage() {
    try {
        const savedCart = localStorage.getItem('webstore_cart');
        if (savedCart) {
            const parsedCart = JSON.parse(savedCart);
            return parsedCart.map(item => ({
                ...item,
                product: products.find(p => p.id === item.productId) || 
                         { id: item.productId, name: 'Ukjent Produkt', price: 0 }
            }));
        }
    } catch (error) {
        console.error('Feil ved lasting av handlekurv fra localStorage:', error);
    }
    return [];
}

🚀 Bruk

Kjøring av applikasjonen

  1. Åpne index.html i en nettleser
  2. Applikasjonen initialiseres automatisk
  3. Naviger mellom produkter, produktdetaljer og handlekurv
  4. Handlekurvtilstand persisteres på tvers av nettlesersesjoner

Nøkkelfunksjoner

  • Produktbrowsing: Vis alle produkter i rutenettlayout
  • Produktdetaljer: Klikk på hvilket som helst produkt for detaljert visning
  • Handlekurv: Legg til, fjern og modifiser antall
  • Persistent handlekurv: Handlekurvinnhold lagret i localStorage
  • Responsiv design: Fungerer på desktop og mobil
  • Brukernotifikasjoner: Tilbakemelding for alle brukerhandlinger

Tilgjengelighet og semantisk HTML

Applikasjonen er bygget med tilgjengelighet i fokus:

Semantiske HTML-elementer

  • <main>, <header>, <footer>, <nav>, <section>, <article>
  • Riktig heading-hierarki (<h1>, <h2>, <h3>)
  • Beskrivende ARIA-attributter

ARIA-funksjoner

  • role-attributter for klargjøring av elementfunksjoner
  • aria-label for beskrivende etiketter
  • aria-live for dynamiske innholdsoppdateringer
  • aria-describedby for tilleggsinformasjon

Tastaturnavigasjon

  • Alle interaktive elementer er tilgjengelige via tastatur
  • Fokusindikatorer for alle interaktive elementer
  • Logisk tab-rekkefølge

🎯 Utdanningsmessige fordeler

MVC-mønsterdemonstrasjon

  • Tydelig separasjon av ansvar
  • Model håndterer data, View håndterer presentasjon, Controller håndterer logikk
  • Demonstrerer hvordan komponenter samhandler i MVC-arkitektur

Moderne JavaScript-funksjoner

  • ES6+-syntaks (arrow-funksjoner, template literals, destructuring)
  • LocalStorage API-bruk
  • Event handling-mønstre
  • Funksjonelle programmeringskonsepter

Webutviklingsfundamentaler

  • DOM-manipuleringsteknikker
  • Event listener-administrasjon
  • Klientsidehåndtering av tilstand
  • HTML-generering og templating
  • CSS-stylingintegrasjon

🔧 Tekniske beslutninger

Hvorfor sentralisert rendering?

  • Konsistens: Alle UI-oppdateringer følger samme mønster
  • Vedlikeholdbarhet: Lett å spore og debugge UI-endringer
  • Skalerbarhet: Enkelt å legge til nye visningstyper
  • Tilstandshåndtering: Klar dataflyt fra model til view

Hvorfor komplett sidegenerering?

  • Enkelhet: Ingen kompleks DOM-diffing eller tilstandssporing
  • Pålitelighet: Fresh render eliminerer foreldede tilstandsproblemer
  • Ytelse: Moderne nettlesere håndterer innerHTML effektivt
  • Debugging: Lett å se nøyaktig hvilken HTML som genereres

Hvorfor LocalStorage?

  • Persistering: Handlekurv overlever nettleseroppstart
  • Enkelhet: Ingen serversidekompleksitet
  • Ytelse: Øyeblikkelige lastetider
  • Utdanningsmessig: Demonstrerer klientsidelagringskonsepter

🎨 Stylingarkitektur

Applikasjonen bruker et rent, moderne CSS-design:

  • Responsive rutenettlayouter
  • Kortbasert produktvisning
  • Konsistent knapp- og formstiling
  • Mobilvennlig navigasjon
  • Glatte overganger og hover-effekter

🔮 Fremtidige forbedringer

Denne MVC-implementeringen fungerer som et grunnlag for progressiv forbedring:

  1. Fase 2: Legg til TypeScript for typesikkerhet
  2. Fase 3: Implementer Vue.js for reaktiv UI
  3. Fase 4: Legg til brukerautentisering
  4. Fase 5: Integrer betalingsbehandling
  5. Fase 6: Legg til produktsøk og filtrering
  6. Fase 7: Implementer ekte backend-API

📚 Læringsutbytte

Ved å studere denne kodebasen vil du forstå:

  • MVC-arkitekturmønsterimplementering
  • Klientsidehåndtering av tilstand
  • Moderne JavaScript-utviklingspraksis
  • HTML-generering og templating-tilnærminger
  • Hendelsesdrevne programmeringsmønstre
  • LocalStorage API-bruk
  • Responsive webdesignprinsipper
  • Tilgjengelighetsstandarder og semantisk HTML

Dette prosjektet er en del av GET Frontend-utviklingslæreplanen og demonstrerer kjerne webutviklingskonsepter gjennom praktisk implementering.