Przejdź do treści
School IT / Przestrzeń do nauki

Wiązanie właściwości [ ]

Klamry wstawiają tekst. Nawiasy kwadratowe robią coś innego: przekazują wartość do właściwości elementu. Przy napisach różnicy nie widać. Przy disabled widać ją natychmiast — i od tej lekcji wygląd strony zacznie zależeć od danych.

Angular 22 [właściwość] [disabled] [class.x] [style.x] [attr.x] 45 min
CEL LEKCJI

Czego się dziś nauczysz

  • Przekażesz wartość z klasy do właściwości elementu zapisem [właściwość]="wyrażenie".
  • Wyjaśnisz, dlaczego disabled="{{ x }}" blokuje przycisk także przy false.
  • Odróżnisz stały atrybut title="…" od wiązania [title]="…".
  • Włączysz i wyłączysz pojedynczą klasę Bootstrapa zapisem [class.nazwa].
  • Ustawisz pojedynczy styl z jednostką zapisem [style.width.rem].
  • Ustawisz atrybut bez odpowiednika we właściwościach zapisem [attr.nazwa].
  • Rozpoznasz błąd składni przy połączeniu [ ] i {{ }}.

Przygotowanie: lekcja 05 — umiesz pokazać wartość pola i użyć operatora ?:. Przewidywany czas: 45 min z zadaniami.

TEORIA

Tekst to nie to samo co wartość

Interpolacja zawsze daje tekst. Jeśli w polu jest liczba 0, w klamrach pojawi się napis "0". Jeśli wartość logiczna false — napis "false".

Dla akapitu to bez znaczenia, bo akapit i tak pokazuje tekst. Ale właściwość disabled pyta o prawdę lub fałsz, a napis "false" jest z jej punktu widzenia prawdziwy — bo jest niepusty. Stąd klasyczny błąd: przycisk zablokowany mimo false.

[właściwość]=”wyrażenie”

Nawiasy kwadratowe znaczą: „to, co w cudzysłowie, jest kodem, nie tekstem”. Angular oblicza wyrażenie i wynik — liczbę, wartość logiczną, tekst — przekazuje do właściwości elementu. W cudzysłowie wolno to samo, co w klamrach z lekcji 05: pola, obliczenia, metody, operator ?:.

porównanie
<button title="Zapisz się">…</button>        <!-- stały tekst "Zapisz się" -->
<button [title]="opis">…</button>           <!-- wartość pola opis -->
<button [title]="'Zapisz się'">…</button>   <!-- stały tekst jako wyrażenie: apostrofy w środku -->

Pytanie kontrolne

Zanim napiszesz wiązanie, zapytaj: „czy ta właściwość oczekuje tekstu?”. Jeśli tak (title, src, alt, placeholder) — zadziałają oba zapisy. Jeśli oczekuje prawdy/fałszu albo liczby (disabled, hidden, checked) — tylko nawiasy kwadratowe.

TEORIA

Odmiany, które przydadzą się od razu

ZapisDo czego
[class.nazwa]="warunek"dodaje jedną klasę CSS, gdy warunek jest prawdziwy, i usuwa, gdy fałszywy; pozostałe klasy elementu zostają
[style.color]="wartosc"ustawia jedną właściwość stylu (tekst, np. 'red')
[style.width.rem]="18"styl razem z jednostką: .px, .rem, .%
[attr.aria-label]="opis"atrybut HTML, który nie ma odpowiednika wśród właściwości elementu

Klasy stałe wpisujesz zwykłym class="…", a te zależne od danych — osobnymi wiązaniami [class.x]. Oba zapisy mogą stać na jednym elemencie i nie przeszkadzają sobie.

PRZYKŁAD 1

Klamry kontra nawiasy kwadratowe

Dwa zapisy, ten sam wynik — przy tekście naprawdę są równoważne.

src/app/nowa-06-1/demo.ts — pełny plik
import { Component } from '@angular/core';

@Component({
    selector: 'app-demo',
    imports: [],
    templateUrl: './demo.html'
})
export class Demo {
    readonly opis = 'Turniej retro, piątek';
}
src/app/nowa-06-1/demo.html — pełny plik
<div class="p-3">
  <p title="{{ opis }}">Najedź myszą — dymek z klamer</p>
  <p [title]="opis">Najedź myszą — dymek z nawiasów</p>
</div>
wynik po najechaniu myszą
Najedź myszą — dymek z klamer      → dymek: Turniej retro, piątek
Najedź myszą — dymek z nawiasów    → dymek: Turniej retro, piątek

Oba akapity pokazują ten sam dymek. Pierwsza forma bywa wygodniejsza, gdy chcesz doklejać coś wokół wartości: title="Wydarzenie: {{ opis }}".

Zatrzymaj się

Pierwszy zapis zawsze tworzy tekst. Drugi przekazuje wartość. Przy napisie nie widać różnicy. Jak myślisz — co się stanie przy wartości false? Sprawdzisz w następnym przykładzie.

PRZYKŁAD 2

Tu klamry już nie wystarczą

Właściwość disabled nie interesuje się tekstem, tylko wartością logiczną.

src/app/nowa-06-2/demo.ts — pełny plik
import { Component } from '@angular/core';

@Component({
    selector: 'app-demo',
    imports: [],
    templateUrl: './demo.html'
})
export class Demo {
    readonly zablokowany = false;
}
src/app/nowa-06-2/demo.html — pełny plik
<div class="p-3">
  <button class="btn btn-primary me-2" [disabled]="zablokowany">Poprawnie</button>
  <button class="btn btn-primary" disabled="{{ zablokowany }}">Źle</button>
</div>
wynik w przeglądarce
[ Poprawnie ]  — aktywny
[ Źle ]        — zablokowany (wyblakły, nie da się kliknąć)

Drugi przycisk jest zablokowany, choć pole ma wartość false. Klamry zamieniły ją na tekst "false", a każdy niepusty tekst w disabled znaczy „zablokuj”.

Zatrzymaj się

Zmień pole na true i sprawdź oba przyciski. Który z nich w ogóle reaguje na zmianę wartości pola?

PRZYKŁAD 3

Wartość policzona w locie

W nawiasach kwadratowych może stać wyrażenie — tak samo jak w klamrach. Jedno pole steruje tu dwiema właściwościami.

src/app/nowa-06-3/demo.ts — pełny plik
import { Component } from '@angular/core';

@Component({
    selector: 'app-demo',
    imports: [],
    templateUrl: './demo.html'
})
export class Demo {
    readonly wolneMiejsca = 0;
    readonly nazwa = 'Noc robotów';
}
src/app/nowa-06-3/demo.html — pełny plik
<div class="card p-3 m-3" style="width: 22rem">
  <h5>{{ nazwa }}</h5>
  <p>Wolne miejsca: {{ wolneMiejsca }}</p>
  <button class="btn btn-primary"
          [disabled]="wolneMiejsca === 0"
          [title]="wolneMiejsca === 0 ? 'Brak miejsc' : 'Kliknij, aby się zapisać'">
    Zapisz się
  </button>
</div>
wynik w przeglądarce
Noc robotów
Wolne miejsca: 0
[ Zapisz się ]  — zablokowany, dymek: Brak miejsc

Zmień wolneMiejsca na 3 — przycisk ożyje, a dymek zmieni treść na „Kliknij, aby się zapisać”. Długi atrybut można rozbić na kilka wierszy — Angular tego nie zauważy.

Zatrzymaj się

Warunek wolneMiejsca === 0 jest zapisany w szablonie dwa razy. Gdzie i jak przeniósłbyś go, żeby był zapisany raz?

PRZYKŁAD 4

Klasa CSS i styl sterowane danymi

Najczęstsze zastosowanie w tym kursie: włączanie i wyłączanie klasy Bootstrapa.

src/app/nowa-06-4/demo.ts — pełny plik
import { Component } from '@angular/core';

@Component({
    selector: 'app-demo',
    imports: [],
    templateUrl: './demo.html'
})
export class Demo {
    readonly ostatnieMiejsca = true;
    readonly szerokosc = 18;
}
src/app/nowa-06-4/demo.html — pełny plik
<div class="card p-3 m-3" [style.width.rem]="szerokosc">
  <h5>Turniej retro</h5>
  <span class="badge" [class.text-bg-danger]="ostatnieMiejsca" [class.text-bg-success]="!ostatnieMiejsca">
    {{ ostatnieMiejsca ? 'Ostatnie miejsca' : 'Wolne miejsca' }}
  </span>
</div>
wynik w przeglądarce
┌──────────────────────┐
│ Turniej retro        │
│ [Ostatnie miejsca]   │  ← czerwona odznaka
└──────────────────────┘   szerokość 18rem

Zmień ostatnieMiejsca na false — odznaka zrobi się zielona, a napis się zmieni. Klasa badge jest wpisana na stałe, kolor sterują dwa wiązania z przeciwnymi warunkami (! to zaprzeczenie). Szerokość karty bierze się z pola: [style.width.rem] dokleja jednostkę za Ciebie.

Zatrzymaj się

Ustaw szerokosc na 30, a potem zmień wiązanie na [style.width]="szerokosc" (bez .rem). Co się stało z szerokością i dlaczego?

ELEMENTY WBUDOWANE

Zestawienie elementów

ElementZnaczenieUwagi
[title]="pole"dymek z wartości polaDla tekstu działa też title="{{ pole }}".
[disabled]="warunek"blokada przycisku lub polaTylko nawiasy kwadratowe.
[hidden]="warunek"ukrycie elementuElement zostaje w HTML, tylko go nie widać.
[class.nazwa]="warunek"włączenie jednej klasyPozostałe klasy zostają.
[style.wlasciwosc]="tekst"jeden stylNp. [style.color]="'red'".
[style.width.rem], .px, .%styl z jednostkąWartość jest liczbą.
[attr.aria-label]atrybut bez właściwościTeż [attr.colspan], [attr.aria-valuenow].
!warunekzaprzeczenietrue ↔ false.
text-bg-success, text-bg-dangerkolor odznakiBootstrap; z lekcji 03.
CZĘSTE BŁĘDY

Zanim utkniesz

ZapisProblem
disabled="{{ x }}"Przycisk zablokowany zawsze, także przy false — tekst "false" jest niepusty.
[title]="Wydarzenie"TS2339: Property 'Wydarzenie’ does not exist. W nawiasach kwadratowych to nazwa pola. Stały tekst: title="Wydarzenie" albo [title]="'Wydarzenie'".
[src]="{{ adres }}"NG5002: Got interpolation ({{}}) where expression was expected. Klamry i nawiasy kwadratowe wykluczają się — wybierz jedno.
[class.badge]="true"Działa, ale to klasa stała — wiązanie tylko zaciemnia kod. Stałe klasy wpisuj w zwykłym class="…".
[style.width]="18"Nic się nie stanie — brakuje jednostki. Napisz [style.width.rem]="18".
[class.text-bg-danger, text-bg-success]Jedno wiązanie = jedna klasa. Dwie klasy to dwa wiązania.
[disabled]="wolne = 0"Pojedyncze = to przypisanie — błąd NG5002. Porównanie to ===.
ZADANIA

Zadania

ZAD 1Dymek z numerem sali★☆☆

Dodaj do karty z przykładu 3 pole sala i pokaż je w dymku przycisku w postaci „Sala 12”. Zrób to dwoma sposobami — klamrami w title i wiązaniem [title] — a jeden z nich zostaw zakomentowany.

Kryterium sukcesu: najechanie na przycisk pokazuje „Sala 12” w obu wersjach.

Podpowiedź

W wiązaniu tekst skleisz plusem: [title]="'Sala ' + sala".

ZAD 2Zapisy otwarte, zapisy zamknięte★☆☆

Dodaj pole zapisyOtwarte (true/false). Przycisk „Zapisz się” ma być zablokowany, gdy zapisy są zamknięte, a pod nim akapit „Zapisy trwają” albo „Zapisy zakończone”. Sprawdź obie wartości pola.

Kryterium sukcesu: przy false przycisk jest wyblakły i widać „Zapisy zakończone”; przy true — odwrotnie.

Podpowiedź

[disabled]="!zapisyOtwarte", a napis — operator ?: z lekcji 05.

ZAD 3Trzy kolory odznaki★★☆

Zrób pole wolneMiejsca i odznakę, która jest zielona przy więcej niż 5 miejscach, żółta przy 1–5 i czerwona przy zerze. Napis w odznace ma pokazywać liczbę miejsc.

Kryterium sukcesu: zmiana liczby w pliku .ts (np. 8, 3, 0) zmienia kolor odznaki bez zmian w szablonie.

Podpowiedź

Trzy osobne wiązania: [class.text-bg-success], [class.text-bg-warning], [class.text-bg-danger], każde z innym warunkiem. Środkowy warunek: wolneMiejsca >= 1 && wolneMiejsca <= 5.

ZAD 4Karta polecana★★☆

Zrób kartę wydarzenia z polami polecane (true/false) i szerokosc (liczba). Gdy wydarzenie jest polecane, karta ma niebieską ramkę (border-primary) i cień (shadow), a nad tytułem pojawia się odznaka „Polecamy”. Szerokość karty w rem ma pochodzić z pola.

Kryterium sukcesu: przełączenie polecane zmienia ramkę, cień i widoczność odznaki; zmiana szerokosc zmienia szerokość karty.

Podpowiedź

Odznakę ukryjesz wiązaniem [hidden]="!polecane". Ramka i cień to dwa wiązania [class.…].

ZAD 5Pasek zapełnienia sali★★★

Zrób pasek postępu Bootstrapa pokazujący, jaka część miejsc jest zajęta. Szerokość paska ma wynikać z pól limit i zapisani, a w pasku ma być napis z procentem. Przy zajętości od 90% pasek ma być czerwony. Zadbaj o to, żeby przy limit = 0 nie powstało dzielenie przez zero.

Kryterium sukcesu: pasek zmienia długość i kolor po zmianie liczb w pliku .ts, a limit = 0 daje pusty pasek z napisem 0%.

Podpowiedź

Budowa paska: <div class="progress"><div class="progress-bar" [style.width.%]="procent()">{{ procent() }}%</div></div>. Metoda procent() zwraca 0, gdy limit jest zerem; czerwień — [class.bg-danger]. Zaokrąglenie: Math.round w metodzie.

ZAD 6Ocena w kolorze★★★

Zrób kartę „Twoja ocena” z polem ocena (1–6). Cyfra oceny ma być duża, a jej kolor zależny od wartości: czerwony dla 1, pomarańczowy dla 2, czarny dla 3–4, zielony dla 5–6. Rozmiar czcionki ma rosnąć z oceną: 1 + ocena * 0.5 rem. Kolor wybierz w metodzie kolor(), która zwraca nazwę koloru CSS. Dodaj też [attr.aria-label] z pełnym opisem, np. „Ocena: 5”.

Kryterium sukcesu: dla ocen 1, 2, 4 i 6 cyfra ma inny kolor i rozmiar, a w narzędziach przeglądarki (F12 → Elements) widać atrybut aria-label.

Podpowiedź

[style.color]="kolor()" i [style.font-size.rem]="1 + ocena * 0.5". W metodzie kilka if z return 'red', return 'orange' itd.

PODSUMOWANIE

Co trzeba zapamiętać

  • {{ }} daje tekst, [ ] przekazuje wartość.
  • Przy właściwościach logicznych, takich jak disabled, klamry zawsze blokują — tylko [disabled] działa poprawnie.
  • W nawiasach kwadratowych stoi wyrażenie: nazwa pola, obliczenie, metoda albo ?:; stały tekst wymaga apostrofów.
  • [class.nazwa] włącza jedną klasę, nie ruszając pozostałych.
  • [style.x.jednostka] ustawia jeden styl z jednostką.
  • [attr.x] ustawia atrybut, którego nie ma wśród właściwości.
  • [ ] i {{ }} w jednym atrybucie dają błąd NG5002.

Sprawdź się: masz pole ukryty = false. Napisz dwa warianty blokowania przycisku tym polem i powiedz, który z nich zadziała zgodnie z oczekiwaniem.

Dokumentacja: angular.dev — wiązanie właściwości i atrybutów.

Postęp zapisuje się w tej przeglądarce.