Lekcja 4. Omówienie gotowego małego programu — kalkulator BMI krok po kroku
ŚredniPo co się tego uczymy?
Zanim zaczniesz uczyć się każdej technologii osobno i szczegółowo (Node.js, TypeScript, Bootstrap, Angular — kolejne lekcje), zobacz najpierw, jak to wszystko wygląda RAZEM, w praktyce, na przykładzie małego, kompletnego programu — kalkulatora BMI. Nie musisz jeszcze rozumieć każdej linijki — chodzi o to, żebyś zobaczył OGÓLNY OBRAZ i wiedział, gdzie w kolejnych lekcjach szukać wyjaśnienia konkretnego fragmentu.
Teoria
Poniższy przykład to kompletny, mały komponent Angular obliczający BMI (wskaźnik masy ciała) na podstawie wzrostu i wagi wpisanych przez użytkownika. Przejdźmy przez niego fragment po fragmencie — z zapowiedzią, w KTÓREJ kolejnej lekcji poznasz dokładnie dany element.
1. Tworzenie komponentu — polecenie w terminalu. Zanim jakikolwiek kod powstanie, w terminalu Visual Studio (albo w terminalu systemowym w folderze projektu klienckiego) wywołuje się polecenie Angular CLI: ng generate component bmi-calculator --standalone. To polecenie URUCHAMIANE JEST przez Node.js (silnik wykonujący JavaScript poza przeglądarką, pełne omówienie w lekcji 5) — samo ng to skrót od Angular CLI, zainstalowanego wcześniej przez npm (menedżer pakietów Node.js). Efekt: Angular SAM tworzy 3 pliki (.ts, .html, .css) z gotowym szkieletem komponentu.
2. Klasa komponentu — plik .ts. Napisana w języku TypeScript (pełne omówienie w lekcji 6) — to JavaScript rozszerzony o typy (number, string...), które pomagają wychwycić błędy ZANIM program się uruchomi. Klasa BmiCalculatorComponent ma pola (height, weight, bmi) przechowujące dane, i metodę obliczBMI() z logiką obliczeniową — dokładnie ten sam podział na "dane" i "zachowanie", którego uczyłeś się przy klasach w dziale programowania obiektowego.
3. Szablon — plik .html. To WIDOK komponentu — zwykły HTML, ale z rozszerzeniami składni Angulara (pełne omówienie w lekcjach 8-10): [(ngModel)]="height" to dwukierunkowe wiązanie danych (wpisany tekst automatycznie aktualizuje pole height w klasie, i odwrotnie), a (click)="obliczBMI()" to podpięcie zdarzenia kliknięcia do metody z klasy TypeScript.
4. Stylowanie — Bootstrap. Klasy takie jak class="container" czy przyciski ze stylem "ładnego, gotowego wyglądu" (widoczne w pełnych projektach w dalszych lekcjach) pochodzą z biblioteki Bootstrap (pełne omówienie w lekcji 7) — zestawu gotowych stylów CSS, dzięki którym nie trzeba samodzielnie projektować wyglądu każdego przycisku czy formularza od zera.
5. Instalacja zależności — npm. Zanim komponent mógłby korzystać z formularzy Angulara (ngModel), trzeba było wcześniej zainstalować odpowiedni pakiet poleceniem npm install @angular/forms — npm (Node Package Manager, część Node.js) to "sklep" z gotowymi bibliotekami, z którego korzysta niemal każdy projekt JavaScript/TypeScript.
Ten sam wzorzec (komenda CLI → plik .ts z logiką → plik .html z widokiem → stylowanie Bootstrapem) powtórzy się w KAŻDYM kolejnym komponencie, który zbudujesz w tym dziale — łącznie z czterema pełnymi projektami na końcu.
Schemat
Terminal (Node.js + npm + Angular CLI)
│ ng generate component bmi-calculator --standalone
▼
Wygenerowane pliki:
┌────────────────────────────┐
│ bmi-calculator.component.ts │ ← TypeScript: dane (height, weight, bmi)
│ │ + logika (obliczBMI()) [lekcja 6]
└──────────────┬───────────────┘
│ templateUrl
▼
┌────────────────────────────┐
│ bmi-calculator.component.html │ ← HTML + składnia Angular:
│ │ [(ngModel)], (click) [lekcje 8-10]
│ │ + klasy Bootstrap (stylowanie) [lekcja 7]
└────────────────────────────────┘
npm install @angular/forms ← instalacja zależności (npm, część Node.js) [lekcja 5]
Przykład z życia
Dokładnie tak, jak przy nauce nowego dania w kuchni najpierw ogląda się gotowy przepis "od góry do dołu", żeby zobaczyć, z jakich składników i kroków się składa, zanim zacznie się uczyć każdej techniki (siekanie, duszenie, pieczenie) osobno — ta lekcja pokazuje "gotowe danie" (kalkulator BMI), żebyś wiedział, DOKĄD zmierzasz, zanim zaczniesz uczyć się poszczególnych "technik kulinarnych" (Node.js, TypeScript, Bootstrap, Angular) w kolejnych lekcjach.
bmi-calculator.component.html
<!-- bmi-calculator.component.html -->
<div class="container text-center mt-5">
<h2>Kalkulator BMI</h2>
<label>Podaj wzrost (cm):</label>
<input type="number" [(ngModel)]="height" placeholder="np. 180" class="form-control" />
<label>Podaj wagę (kg):</label>
<input type="number" [(ngModel)]="weight" placeholder="np. 75" class="form-control" />
<button (click)="obliczBMI()" class="btn btn-primary mt-3">Oblicz BMI</button>
<p *ngIf="bmi !== null" class="mt-3">
Twoje BMI to: <strong>{{ bmi.toFixed(1) }}</strong>
</p>
</div>
bmi-calculator.component.ts
// bmi-calculator.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-bmi-calculator',
standalone: true,
imports: [CommonModule, FormsModule],
templateUrl: './bmi-calculator.component.html',
styleUrls: ['./bmi-calculator.component.css']
})
export class BmiCalculatorComponent {
height: number = 0;
weight: number = 0;
bmi: number | null = null;
obliczBMI() {
if (this.height > 0 && this.weight > 0) {
const heightInMeters = this.height / 100;
this.bmi = this.weight / (heightInMeters * heightInMeters);
}
}
}
Komentarz i wyjaśnienie kodu
imports: [CommonModule, FormsModule] pokazuje ważną cechę nowoczesnego Angulara (komponenty "standalone") — każdy komponent JAWNIE deklaruje, jakich DODATKOWYCH możliwości potrzebuje: CommonModule daje dostęp do dyrektyw takich jak *ngIf (warunkowe pokazywanie fragmentu HTML), a FormsModule daje dostęp do [(ngModel)] (dwukierunkowe wiązanie pól formularza). Bez tych importów odpowiednie znaczniki w HTML po prostu by nie zadziałały.
height: number = 0; i bmi: number | null = null; to przykład składni TypeScript — po dwukropku podana jest DOKŁADNA nazwa typu danych (number), a number | null oznacza "liczba ALBO brak wartości" (podobnie do double? z C#, które poznałeś w dziale MAUI). Ta jedna linijka pokazuje różnicę między TypeScript a zwykłym JavaScript, gdzie takich deklaracji typów by nie było.
*ngIf="bmi !== null" w szablonie HTML to dyrektywa strukturalna Angulara — CAŁY fragment <p> pojawia się w przeglądarce TYLKO wtedy, gdy warunek jest prawdziwy (czyli dopiero po kliknięciu przycisku i obliczeniu wyniku) — analogiczne do @if z lekcji o Razor w innych częściach tego kursu, tylko w składni Angulara.
Ćwiczenie samodzielne
Przepisz (nie kopiuj-wklej, tylko przepisz ręcznie, żeby lepiej zapamiętać składnię) powyższy komponent w nowym projekcie Angular, i uruchom go — sprawdź, że wpisanie wzrostu i wagi, a potem kliknięcie przycisku, poprawnie wylicza i wyświetla BMI.
Zadania do pracy własnej
Znajdź w kodzie WSZYSTKIE miejsca, gdzie występuje składnia specyficzna dla Angulara (nie zwykły HTML/TypeScript) i wypisz je w tabeli z krótkim opisem, co robi każda z nich.
Dodaj do komponentu kategorię BMI (niedowaga/norma/nadwaga/otyłość) jako nowe pole klasy, wyliczane w metodzie
obliczBMI(), i wyświetl ją obok liczbowego wyniku w szablonie HTML.Zainstaluj wymagany pakiet (
npm install @angular/forms, jeśli jeszcze nie masz) i rozbuduj przykład o walidację: przycisk "Oblicz BMI" powinien być NIEAKTYWNY ([disabled]), dopóki oba pola (wzrost, waga) nie mają wartości większej od zera.
Typowe błędy
Próba użycia [(ngModel)] bez zaimportowania FormsModule — Angular zgłosi błąd kompilacji, że nie rozpoznaje tego atrybutu; to bardzo częsty błąd na start, bo łatwo zapomnieć o imporcie w standalone components.
Oczekiwanie, że zrozumiesz KAŻDY szczegół już w tej lekcji — to normalne, że wiele elementów (dekorator @Component, *ngIf, [(ngModel)]) jest na razie tylko ZASYGNALIZowanych; pełne wyjaśnienie każdego z nich znajdziesz w konkretnie wskazanej, kolejnej lekcji.
Nawiązanie do egzaminu zawodowego
Ta lekcja daje "mapę drogową" dla całej reszty działu — każdy element pokazany tutaj pobieżnie zostanie dokładnie wyjaśniony w kolejnych lekcjach (5-10), a sam ten kalkulator BMI, w pełnej, rozbudowanej wersji z backendem ASP.NET Core, powróci jako pierwszy z czterech projektów końcowych (lekcja 20).