Interpolacja {{ }} — dane z klasy na ekranie
Dane leżą w klasie, a użytkownik patrzy na szablon. Poznasz najprostszy most między nimi: podwójne klamry. Zobaczysz, co wolno w nie wpisać, czego nie wolno i jak odczytać komunikat, gdy przesadzisz.
Czego się dziś nauczysz
- Pokażesz w szablonie wartość pola klasy za pomocą
{{ }}. - Wyjaśnisz, dlaczego w szablonie nie piszemy
this. - Umieścisz w klamrach obliczenie, wywołanie metody i metodę tekstu, np.
toUpperCase(). - Wybierzesz jeden z dwóch napisów operatorem
warunek ? a : b. - Sformatujesz liczbę do dwóch miejsc po przecinku metodą
toFixed(2). - Rozpoznasz zapisy, których Angular w klamrach nie przyjmie, i odczytasz komunikat błędu.
- Odróżnisz błąd kompilacji od ostrzeżenia NG8117 przy metodzie bez nawiasów.
Przygotowanie: lekcje 01–04 — masz projekt z Bootstrapem i umiesz uruchomić przykład przez komponent Demo. Przewidywany czas: 45 min z zadaniami.
Skąd szablon bierze dane
Do tej pory wpisywałeś teksty wprost w HTML. Działa, dopóki nic się nie zmienia. Ale nazwa wydarzenia, liczba wolnych miejsc czy cena biletu będą się zmieniać — i nie chcesz przy każdej zmianie szukać ich w dziesięciu miejscach szablonu.
Dlatego dane trzymamy w klasie komponentu, a w szablonie zostawiamy tylko miejsce, w które Angular je wstawi. To miejsce oznaczamy podwójnymi klamrami — to interpolacja.
<p>Tekst stały {{ wyrażenie }} dalszy tekst stały</p>
Angular oblicza to, co stoi między klamrami, zamienia wynik na tekst i wstawia go w to miejsce. Gdy wartość pola się zmieni, napis na ekranie zmieni się razem z nią.
Co wolno w klamrach, a czego nie
Klamry służą do pokazywania. Wolno w nich odczytać wartość i coś policzyć. Zmienianie danych to zadanie metod w klasie.
| Zapis w klamrach | Wolno? | Uwagi |
|---|---|---|
{{ nazwa }} | tak | pole klasy, bez this |
{{ cena * sztuki }} | tak | działania arytmetyczne |
{{ razem() }} | tak | wywołanie metody — zawsze z nawiasami |
{{ imie.toUpperCase() }}, {{ imie.length }} | tak | metody i właściwości tekstu znane z TypeScriptu |
{{ cena.toFixed(2) }} | tak | liczba z dwoma miejscami po kropce |
{{ wolne > 0 ? 'są miejsca' : 'brak' }} | tak | operator warunkowy wybiera jeden z dwóch wyników |
{{ licznik = 5 }}, {{ licznik++ }} | nie | przypisanie — błąd NG5002 |
{{ if (x) { } }} | nie | instrukcje nie są wyrażeniami (warunki w szablonie: lekcja 12) |
{{ Math.round(cena) }} | nie | szablon widzi tylko składowe swojej klasy, nie obiekty globalne |
Bez this
W metodach klasy piszesz this.nazwa. W szablonie — samo nazwa: Angular wie, że chodzi o ten komponent. Zapis {{ this.nazwa }} też się skompiluje, ale nikt go tak nie pisze, więc i my nie będziemy.
Metoda potrzebuje nawiasów
{{ razem() }} pokaże wynik. {{ razem }} pokaże na ekranie… treść funkcji jako tekst. To nie jest błąd kompilacji — terminal pokaże tylko żółte ostrzeżenie NG8117, dlatego tak łatwo je przeoczyć.
Operator warunkowy ?:
Zapis warunek ? a : b znasz z TypeScriptu: jeśli warunek jest prawdziwy, wynikiem jest a, w przeciwnym razie b. To wyrażenie, więc wolno go użyć w klamrach. Przy jednym wyborze z dwóch jest czytelny; przy trzech i więcej możliwościach przenieś decyzję do metody w klasie.
Pole klasy na ekranie
Klasa przechowuje dane, szablon je pokazuje. Klamry łączą jedno z drugim — także w środku zdania.
import { Component } from '@angular/core';
@Component({
selector: 'app-demo',
imports: [],
templateUrl: './demo.html'
})
export class Demo {
readonly nazwa = 'Turniej retro';
readonly sala = 12;
readonly wolneMiejsca = 2;
}
<div class="card p-3 m-3" style="width: 22rem">
<h5>{{ nazwa }}</h5>
<p>Sala {{ sala }}, wolne miejsca: {{ wolneMiejsca }}</p>
</div>
Turniej retro
Sala 12, wolne miejsca: 2
Pola są readonly, bo w tej lekcji tylko je pokazujemy. Zmień wartość sala w pliku .ts i zapisz — ekran zmieni się sam.
Zatrzymaj się
W szablonie nie ma słowa this, choć w metodzie klasy napisałbyś this.nazwa. Skąd szablon wie, której klasy pola ma szukać?
W klamrach może być wyrażenie
Między klamrami nie musi stać sama nazwa pola. Może tam być obliczenie, wywołanie metody klasy albo metoda tekstu. Lista to klasy Bootstrapa list-group i list-group-item — każdy element w osobnym wierszu z ramką.
import { Component } from '@angular/core';
@Component({
selector: 'app-demo',
imports: [],
templateUrl: './demo.html'
})
export class Demo {
readonly cena = 12.5;
readonly sztuki = 3;
readonly imie = 'ala';
razem(): number {
return this.cena * this.sztuki;
}
}
<ul class="list-group m-3" style="width: 22rem">
<li class="list-group-item">Cena: {{ cena }} zł</li>
<li class="list-group-item">Sztuk: {{ sztuki }}</li>
<li class="list-group-item">Razem: {{ cena * sztuki }} zł</li>
<li class="list-group-item">Razem z metody: {{ razem() }} zł</li>
<li class="list-group-item">Wielkimi literami: {{ imie.toUpperCase() }}</li>
<li class="list-group-item">Długość imienia: {{ imie.length }}</li>
</ul>
Cena: 12.5 zł
Sztuk: 3
Razem: 37.5 zł
Razem z metody: 37.5 zł
Wielkimi literami: ALA
Długość imienia: 3
Trzeci i czwarty wiersz dają to samo — raz policzone w szablonie, raz w metodzie. Liczby mają kropkę zamiast przecinka, bo to zapis JavaScriptu; polski format poznasz w lekcji 16.
Zatrzymaj się
Skoro obie drogi dają ten sam wynik, po co komu metoda? Wyobraź sobie, że wzór trzeba zmienić, a stoi w pięciu miejscach szablonu.
Czego w klamrach nie wolno
Interpolacja pokazuje wartość, ale jej nie zmienia. Zacznij od wersji poprawnej, a potem po kolei wklejaj zapisy błędne i czytaj komunikaty.
import { Component } from '@angular/core';
@Component({
selector: 'app-demo',
imports: [],
templateUrl: './demo.html'
})
export class Demo {
licznik = 0;
readonly teraz = new Date();
}
<div class="p-3">
<p>Poprawnie: {{ licznik }}</p>
<p>Też poprawnie: {{ licznik + 1 }}</p>
<p>Data działa, ale wygląda brzydko: {{ teraz }}</p>
</div>
<p>{{ licznik = 5 }}</p>
<p>{{ licznik++ }}</p>
<p>{{ Math.round(licznik) }}</p>
✘ [ERROR] NG5002: Parser Error: Bindings cannot contain assignments at column 12 in [ licznik = 5 ]
✘ [ERROR] NG5002: Parser Error: Unexpected end of expression: licznik++
✘ [ERROR] TS2339: Property 'Math' does not exist on type 'Demo'.
Każdy komunikat podaje plik i wiersz. Bindings cannot contain assignments znaczy dosłownie „wiązania nie mogą zawierać przypisań”. Property 'Math’ does not exist on type 'Demo’ — szablon szuka Math w klasie Demo i go nie znajduje.
Zatrzymaj się
Data wypisuje się w długiej, angielskiej postaci, np. Wed Oct 07 2026 14:30:00 GMT+0200. Zapamiętaj to — w lekcji 16 poprawimy ją jednym słowem.
Wybór napisu i ładna cena
Dwa wyrażenia, które w tym kursie zobaczysz setki razy: operator ?:, który wybiera napis, i toFixed(2), który pokazuje cenę z groszami.
import { Component } from '@angular/core';
@Component({
selector: 'app-demo',
imports: [],
templateUrl: './demo.html'
})
export class Demo {
readonly nazwa = 'Warsztat druku 3D';
readonly cena = 15;
readonly wolneMiejsca = 0;
opis(): string {
return this.nazwa + ' — ' + this.cena.toFixed(2) + ' zł';
}
}
<div class="card p-3 m-3" style="width: 24rem">
<h5>{{ nazwa }}</h5>
<p class="mb-1">Cena: {{ cena.toFixed(2) }} zł</p>
<p class="mb-1">Status: {{ wolneMiejsca > 0 ? 'są wolne miejsca' : 'brak miejsc' }}</p>
<p class="mb-1">Liter w nazwie: {{ nazwa.length }}</p>
<p class="mb-0 text-muted">{{ opis() }}</p>
</div>
Warsztat druku 3D
Cena: 15.00 zł
Status: brak miejsc
Liter w nazwie: 17
Warsztat druku 3D — 15.00 zł
15 zamienia się w 15.00, bo toFixed(2) zawsze dopisuje dwa miejsca po kropce. Zmień wolneMiejsca na 4 i zapisz — status zmieni się na „są wolne miejsca”. Metoda opis() składa tekst z kilku pól — w klasie, więc szablon zostaje krótki.
Zatrzymaj się
Usuń nawiasy w {{ opis() }}, zostawiając {{ opis }}. Co pokazała przeglądarka i jaki kod ma żółte ostrzeżenie w terminalu? Przywróć nawiasy.
Zestawienie elementów
| Element | Znaczenie | Uwagi |
|---|---|---|
{{ pole }} | wartość pola na ekranie | Bez this. |
{{ a * b }} | wynik obliczenia | Krótkie obliczenia; dłuższe do metody. |
{{ metoda() }} | wynik metody klasy | Bez nawiasów — ostrzeżenie NG8117. |
tekst.toUpperCase() | tekst wielkimi literami | toLowerCase() — małymi. |
tekst.length | liczba znaków | Właściwość, bez nawiasów. |
liczba.toFixed(2) | liczba jako tekst z 2 miejscami po kropce | Zaokrągla: (2.345).toFixed(2) → 2.35. |
warunek ? a : b | jeden z dwóch wyników | Więcej przypadków — metoda w klasie. |
readonly | pole, którego nie zmienisz | Do danych tylko do pokazania. |
list-group, list-group-item | lista Bootstrapa z ramkami | Na ul i li. |
| NG5002 | błąd składni w szablonie | Np. przypisanie w klamrach. |
| TS2339 | nie ma takiej składowej | Literówka albo obiekt spoza klasy. |
| NG8117 | metoda bez nawiasów | Ostrzeżenie, nie błąd. |
Zanim utkniesz
| Zapis | Problem |
|---|---|
{{ razem }} zamiast {{ razem() }} | Na ekranie treść funkcji zamiast liczby, w terminalu tylko ostrzeżenie NG8117. Najczęstsza pomyłka w całym kursie. |
{{ licznik = 5 }} | Błąd NG5002 — przypisanie w interpolacji jest zabronione. Zmiana wartości należy do metod. |
{{ Math.round(x) }} | TS2339 — szablon nie widzi obiektów globalnych. Zaokrąglij w metodzie klasy. |
Literówka w nazwie pola, np. {{ nazwaa }} | TS2339 z numerem wiersza — szablony są sprawdzane tak samo jak kod. |
{ nazwa } — pojedyncze klamry | Na ekranie pojawi się dosłownie { nazwa }. Klamry muszą być podwójne. |
{{ cena.toFixed(2) }} przy cenie '12.5' w cudzysłowie | Tekst nie ma metody toFixed — błąd TS2339. Liczby zapisuj bez cudzysłowu. |
Trzy zagnieżdżone ?: w jednych klamrach | Działa, ale nikt tego nie przeczyta. Przenieś decyzję do metody z if. |
Zadania
Zrób komponent z kartą Bootstrapa i trzema polami klasy: nazwa wydarzenia, dzień tygodnia i liczba miejsc. Wszystkie trzy pokaż w szablonie — nazwę w nagłówku, pozostałe w jednym zdaniu, np. „Spotykamy się w czwartek, miejsc: 16”.
Kryterium sukcesu: na ekranie widać trzy wartości pobrane z klasy; zmiana pola w pliku .ts zmienia ekran.
Podpowiedź
Zacznij od przykładu 1 i zmień nazwy pól. Wartości w zdaniu wstawiasz klamrami w środku tekstu.
Zrób kartę „legitymacji” z polami: imie, nazwisko, klasa, rokUrodzenia i rokBiezacy. Pokaż: imię i nazwisko w jednym wierszu, nazwisko dodatkowo wielkimi literami, klasę oraz wiek policzony w szablonie.
Kryterium sukcesu: wiek zgadza się z różnicą lat, a nazwisko w drugim wierszu jest wielkimi literami.
Podpowiedź
{{ rokBiezacy - rokUrodzenia }} oraz {{ nazwisko.toUpperCase() }}.
Dodaj pola cena i rabatProcent. Pokaż cenę przed rabatem, kwotę rabatu i cenę po rabacie, każdą z dwoma miejscami po kropce. Najpierw policz wszystko w szablonie. Potem przenieś obliczenia do metod kwotaRabatu() i poRabacie() i porównaj długość szablonu. Zostaw w pliku wersję z metodami.
Kryterium sukcesu: obie wersje dają te same liczby, np. dla 80 zł i 15% — 12.00 zł rabatu i 68.00 zł po rabacie.
Podpowiedź
Kwota rabatu to cena * rabatProcent / 100. Metoda poRabacie() może wywołać this.kwotaRabatu().
Zrób paragon jako listę list-group: trzy produkty (np. drożdżówka, sok, kanapka), każdy ma pole z ceną i pole z ilością. W każdym wierszu pokaż nazwę, ilość, cenę jednostkową i wartość pozycji. W ostatnim, pogrubionym wierszu pokaż sumę obliczoną metodą suma(). Wszystkie kwoty z dwoma miejscami po kropce.
Kryterium sukcesu: suma zgadza się z ręcznym rachunkiem, a po zmianie ilości w pliku .ts zmienia się wartość pozycji i suma.
Podpowiedź
Jeśli suma() zwraca liczbę, w szablonie dopisz .toFixed(2): {{ suma().toFixed(2) }}. Pogrubienie — klasa fw-bold.
Wydarzenie ma pola limit i zapisani. Pokaż liczbę wolnych miejsc, zajętość w procentach (bez miejsc po przecinku) i komunikat z metody komunikat(): „Zapisy otwarte”, gdy wolnych jest więcej niż 5, „Ostatnie miejsca” przy 1–5 i „Brak miejsc” przy zerze. Sprawdź wszystkie trzy przypadki, zmieniając zapisani.
Kryterium sukcesu: dla limit = 20 i zapisani równego 10, 17 i 20 widać trzy różne komunikaty i zajętość 50%, 85%, 100%.
Podpowiedź
Trzy przypadki to za dużo na ?: — w metodzie użyj if i return. Procent: (zapisani / limit * 100).toFixed(0).
Wklej do szablonu poniższy fragment (pola nazwa, cena, sztuki i metoda razem() są w klasie). Zanim zapiszesz, przewidź w zeszycie, który wiersz da błąd, który ostrzeżenie, a który zadziała. Potem sprawdź, zapisz kody komunikatów i popraw każdy wiersz tak, żeby pokazywał to, co obiecuje.
<p>{{ nazwa.toUppercase() }}</p>
<p>Razem: {{ razem }}</p>
<p>Po zaokrągleniu: {{ Math.round(cena) }}</p>
<p>Dodaj sztukę: {{ sztuki = sztuki + 1 }}</p>
<p>Cena: {{ cena.toFixed(2) }} zł</p>
Kryterium sukcesu: tabelka z pięcioma wierszami (przewidywanie, komunikat, poprawka), a szablon na koniec kompiluje się bez błędów i ostrzeżeń.
Podpowiedź
Jeden wiersz jest poprawny. Wielkość liter w nazwie metody ma znaczenie. Zaokrąglenie przenieś do metody klasy, a „dodaj sztukę” zamień na pokazanie sztuki + 1.
Co trzeba zapamiętać
{{ pole }}wstawia wartość z klasy do szablonu; w szablonie nie piszemythis.- W klamrach może stać obliczenie, metoda klasy albo metoda tekstu czy liczby.
- Metodę wywołujesz z nawiasami; bez nich zobaczysz treść funkcji i ostrzeżenie NG8117.
warunek ? a : bwybiera jeden z dwóch wyników; więcej przypadków — metoda zif.toFixed(2)pokazuje liczbę z dwoma miejscami po kropce.- Interpolacja niczego nie zmienia: przypisania dają błąd NG5002.
- Szablon widzi tylko składowe swojej klasy —
Mathi inne obiekty globalne nie są dostępne.
Sprawdź się: masz pole cena = 20 i metodę zRabatem(). Co pokaże {{ zRabatem }}, a co {{ zRabatem() }}?
Dokumentacja: angular.dev — wiązanie danych w szablonie.