Trudny / egzaminacyjny · lekcja 22

Projekt 3: Sklep internetowy (e-sklep) — katalog, wyszukiwanie i koszyk

Podstawa programowa INF.04.7.3 wprost wymienia "funkcjonalności e-sklepu" jako jeden z typów aplikacji, które powinieneś umieć zaprogramować. Ten projekt buduje WŁAŚNIE to — prawdziwy, kompletny sklep internetowy z katalogiem produktów podzielonym na kategorie...

Zacznij tutaj

Po co się tego uczymy?

Podstawa programowa INF.04.7.3 wprost wymienia "funkcjonalności e-sklepu" jako jeden z typów aplikacji, które powinieneś umieć zaprogramować. Ten projekt buduje WŁAŚNIE to — prawdziwy, kompletny sklep internetowy z katalogiem produktów podzielonym na kategorie, wyszukiwarką, i koszykiem zakupowym z podsumowaniem zamówienia.

Wprowadzenie

Teoria

Wymagania projektu:

  • Katalog produktów podzielony na kategorie, z możliwością filtrowania po kategorii;
  • Wyszukiwarka — pole tekstowe filtrujące produkty po nazwie NA BIEŻĄCO, w miarę pisania;
  • Koszyk — dodawanie produktów, zmiana ilości, usuwanie pozycji, widoczny na każdej stronie licznik produktów w koszyku;
  • Podsumowanie zamówienia i "checkout" — ekran z listą zamówionych produktów, sumą do zapłaty, i formularzem danych do wysyłki (imię, adres) z walidacją.

Wyszukiwanie NA BIEŻĄCO — debounceTime. Filtrowanie produktów przy KAŻDYM naciśnięciu klawisza (bez czekania na kliknięcie przycisku "Szukaj") to standardowa funkcjonalność e-sklepu. Naiwna implementacja wysyłałaby żądanie do backendu przy KAŻDEJ literze — marnując zasoby. RxJS (biblioteka używana wewnętrznie przez Angular, poznana pobieżnie przy Observable w lekcji 12) udostępnia operator debounceTime(300), który CZEKA 300 milisekund od OSTATNIEGO naciśnięcia klawisza, zanim faktycznie wykona wyszukiwanie — jeśli użytkownik pisze dalej, poprzednie oczekiwanie jest anulowane. Efekt: żądanie wysyłane jest dopiero, gdy użytkownik faktycznie PRZESTANIE pisać (choćby na chwilę), a nie po każdej literze.

Filtrowanie po stronie backendu (query string). Zamiast pobierać WSZYSTKIE produkty i filtrować je w Angularze (co przy dużym katalogu byłoby nieefektywne), backend przyjmuje parametry zapytania: GET /api/produkty?kategoria=elektronika&szukaj=klawiatura — kontroler odczytuje je jako zwykłe parametry metody C# (ASP.NET Core SAM mapuje parametry query string na parametry akcji o tej samej nazwie) i filtruje zapytanie LINQ/EF Core PRZED wysłaniem wyniku.

Koszyk jako serwis Angular (dokładnie ten wzorzec z lekcji 10 i projektu restauracji, lekcja 23) — KoszykService przechowuje aktualnie dodane produkty i ich ilości, udostępnia metody dodaj(), usun(), obliczSume(), i jest wstrzykiwany zarówno w komponent nagłówka (pokazujący licznik), jak i w komponent samego koszyka/checkout.

Zobacz zależności

Schemat

KatalogComponent
  <input [(ngModel)]="fraza" (ngModelChange)="naZmianeSzukania($event)">
        │
        │  RxJS: this.szukajZmiana$.pipe(debounceTime(300)).subscribe(...)
        ▼
  GET /api/produkty?kategoria=X&szukaj=Y
        │
        ▼
ASP.NET Core: ProduktyController.GetWszystkie(string? kategoria, string? szukaj)
        │
        ├── query = context.Produkty.AsQueryable();
        ├── if (kategoria != null) query = query.Where(p => p.Kategoria == kategoria);
        ├── if (szukaj != null) query = query.Where(p => p.Nazwa.Contains(szukaj));
        │
        ▼
   return Ok(await query.ToListAsync());

KoszykService (singleton)
  dodaj(produkt) / usun(id) / obliczSume()
        │           │
        ▼           ▼
NaglowekComponent   KoszykComponent (checkout)
(licznik produktów) (lista + suma + formularz danych wysyłki)

Połącz z praktyką

Przykład z życia

Każdy sklep internetowy (Allegro, Amazon, mniejsze sklepy branżowe) działa dokładnie na tej zasadzie: katalog z kategoriami i wyszukiwarką, koszyk widoczny w nagłówku niezależnie od tego, którą podstronę akurat przeglądasz, i finalne podsumowanie przed złożeniem zamówienia — to jeden z najbardziej rozpoznawalnych i praktycznych wzorców w całym świecie aplikacji webowych.