Zmienne szablonowe – #referencja

Zmienne szablonowe pozwalają „złapać” element HTML lub komponent za pomocą nazwy z kratką i używać go w innych miejscach szablonu. To proste narzędzie, które oszczędza dużo kodu TypeScript.

#zmienna template reference zdarzenia ViewChild
01

Czym jest zmienna szablonowa?

Wyobraź sobie, że chcesz wziąć to co użytkownik wpisał w pole tekstowe i wyświetlić to w innym miejscu strony – bez pisania ani jednej linii TypeScript. Właśnie do tego służą zmienne szablonowe.

Zmienna szablonowa to etykieta przyklejona do elementu HTML. Dzięki niej możesz odwoływać się do tego elementu – czytać jego wartość, wywoływać jego metody – bezpośrednio w kodzie HTML, bez pośrednictwa pliku .ts.

<input #pole>
nadajemy nazwę elementowi
pole.value
odczytujemy wartość
{{ pole.value }}
wyświetlamy w szablonie
Porównanie do C#

W WPF każdy element ma właściwość Name lub x:Name i odwołujesz się do niego z C# przez tę nazwę. Zmienna szablonowa Angulara działa podobnie – daje elementowi nazwę – ale używasz jej bezpośrednio w HTML, nie w TypeScript.

02

Składnia – znak # przed nazwą

Zmienną szablonową tworzymy dodając #nazwaZmiennej jako atrybut dowolnego elementu HTML. Nazwa może być dowolna – ważne żeby zaczynała się od #.

html/składnia.html HTML
<!-- Zmienna szablonowa na elemencie input -->
<input #mojePolee type="text">

<!-- Zmienna szablonowa na przycisku -->
<button #mojPrzycisk class="btn btn-primary">Kliknij</button>

<!-- Zmienna szablonowa na nagłówku -->
<h2 #tytul>Nagłówek strony</h2>

<!-- Teraz możemy używać tych zmiennych w CAŁYM szablonie -->
<p>Wpisałeś: {{ mojePolee.value }}</p>
<p>Tekst przycisku: {{ mojPrzycisk.textContent }}</p>
<p>Nagłówek: {{ tytul.textContent }}</p>
Zmienna szablonowa ≠ zmienna CSS

Znak # jest też używany w CSS do selektorów ID (np. #naglowek { color: red; }). To dwa różne zastosowania tego samego znaku – w Angularze #nazwa jako atrybut HTML tworzy zmienną szablonową, a nie selektor CSS.

03

Odczyt wartości pola formularza

Najczęstsze zastosowanie zmiennych szablonowych to odczytywanie tego co użytkownik wpisał w pole input. Przez zmienną szablonową mamy dostęp do właściwości value – aktualnej zawartości pola.

Poniższy przykład wyświetla na żywo to co piszesz w polu tekstowym – bez żadnego kodu w pliku .ts:

html/app.component.html HTML
<div class="container mt-4">

  <label class="form-label">Wpisz swoje imię:</label>
  <input
    #imieInput
    type="text"
    class="form-control"
    (input)="''"
  >

  <!-- Wyświetlamy wartość pola przez zmienną szablonową -->
  <p class="mt-3">
    Wpisałeś: <strong>{{ imieInput.value }}</strong>
  </p>

</div>
Co robi (input)="''"?

To zdarzenie (input) – reaguje na każde wciśnięcie klawisza w polu. Przypisujemy mu pusty string '' żeby Angular wiedział, że ma odświeżyć widok po każdym znaku. Bez tego {{ imieInput.value }} nie zaktualizuje się na żywo. O zdarzeniach (event binding) dowiesz się więcej w osobnym materiale.

Właściwości dostępne przez zmienną szablonową

WłaściwośćCo zwraca?Przykład
.value Wartość wpisana w pole input imieInput.value
.textContent Tekst wewnątrz elementu (np. <p>, <h1>) naglowek.textContent
.checked Czy checkbox jest zaznaczony (true/false) zgodaCheckbox.checked
.disabled Czy element jest zablokowany przycisk.disabled
04

Przekazanie wartości do metody

Zmienną szablonową możemy też przekazać jako argument do metody komponentu. To połączenie szablonu z TypeScriptem – zamiast odczytywać wartość w HTML, oddajemy ją do przetworzenia klasie.

Klasyczny przykład: pole tekstowe i przycisk. Po kliknięciu przycisku wartość z pola trafia do metody w TypeScript:

ts/app.component.ts TS
export class AppComponent {
  wynik: string = '';

  przywitaj(imie: string): void {
    this.wynik = `Cześć, ${imie}! Witaj w Angularze!`;
  }
}
html/app.component.html HTML
<div class="container mt-4">

  <div class="input-group mb-3">
    <!-- 1. Tworzymy zmienną szablonową #imieRef -->
    <input #imieRef type="text" class="form-control" placeholder="Wpisz imię">

    <!-- 2. Po kliknięciu przekazujemy .value do metody -->
    <button
      class="btn btn-primary"
      (click)="przywitaj(imieRef.value)"
    >
      Przywitaj
    </button>
  </div>

  <!-- 3. Wynik metody wyświetlamy przez interpolację -->
  <p class="alert alert-success">{{ wynik }}</p>

</div>
#imieRef
zmienna szablonowa
imieRef.value
wartość pola
przywitaj()
metoda w .ts
{{ wynik }}
wyświetlenie
Wskazówka – czyszczenie pola po kliknięciu

Po wywołaniu metody możesz wyczyścić pole dodając do obsługi kliknięcia przypisanie imieRef.value = '':

(click)="przywitaj(imieRef.value); imieRef.value = ''"

Średnik pozwala wykonać dwie instrukcje w jednej obsłudze zdarzenia.

05

Wiele zmiennych szablonowych naraz

W jednym szablonie możemy mieć dowolną liczbę zmiennych szablonowych. Każda musi mieć unikalną nazwę w obrębie szablonu.

Przykład prostego mini-kalkulatora – dwa pola i przycisk. Wszystko bez żadnej zmiennej w klasie, tylko przez zmienne szablonowe i wyrażenie w szablonie:

ts/app.component.ts TS
export class AppComponent {
  // Klasa jest pusta – całość działa przez zmienne szablonowe!
}
html/app.component.html HTML
<div class="container mt-4">
  <h4>Mini kalkulator</h4>

  <div class="row g-2 align-items-center">
    <div class="col-auto">
      <input #liczbaA type="number" class="form-control"
             (input)="''" value="0">
    </div>
    <div class="col-auto"><span>+</span></div>
    <div class="col-auto">
      <input #liczbaB type="number" class="form-control"
             (input)="''" value="0">
    </div>
    <div class="col-auto"><span>=</span></div>
    <div class="col-auto">
      <!-- Suma obliczana bezpośrednio w szablonie -->
      <span class="fs-4 fw-bold text-success">
        {{ +liczbaA.value + +liczbaB.value }}
      </span>
    </div>
  </div>
</div>
Dlaczego +liczbaA.value a nie samo liczbaA.value?

Właściwość .value zwraca zawsze string (tekst), nawet gdy pole jest typu number. Operator + przed wartością konwertuje string na liczbę. Bez tego zamiast dodawania dostałbyś sklejanie tekstu: "5" + "3" = "53" zamiast 8.

06

Zasięg zmiennej szablonowej

Zmienna szablonowa jest dostępna w całym szablonie komponentu, ale z jednym ważnym wyjątkiem – nie działa wewnątrz zagnieżdżonych struktur takich jak @if czy @for, jeśli jest zdefiniowana poza nimi (i odwrotnie).

✅ Zmienna dostępna w całym szablonie

<input #pole type="text">

<!-- Działa – pole i p są na tym samym poziomie -->
<p>{{ pole.value }}</p>
<button (click)="zapisz(pole.value)">Zapisz</button>

❌ Zmienna poza zasięgiem @if

@if (warunek) {
  <input #pole type="text">
}

<!-- Nie działa! pole jest wewnątrz @if -->
<p>{{ pole.value }}</p>
Praktyczna zasada

Zmienną szablonową definiuj w tym samym bloku (@if, @for lub główny szablon) w którym jej używasz. Jeśli potrzebujesz wartości pola w wielu miejscach szablonu – umieść input poza blokami warunkowymi.

07

Częste błędy

❌ Błąd 1 – Dwie zmienne o tej samej nazwie

❌ Źle – duplikat nazwy

<input #pole type="text">
<input #pole type="number">
<!-- Angular nie wie, do którego się odwołujemy -->

✅ Dobrze – unikalne nazwy

<input #nazwaInput type="text">
<input #wiekInput type="number">

❌ Błąd 2 – Brak zdarzenia przy wyświetlaniu na żywo

❌ Pole nie aktualizuje się na żywo

<!-- Brak zdarzenia – Angular nie odświeża widoku -->
<input #imie type="text">
<p>{{ imie.value }}</p>
<!-- Wynik nie zmieni się po wpisaniu tekstu -->

✅ Zdarzenie (input) wymusza odświeżenie

<input #imie type="text" (input)="''">
<p>{{ imie.value }}</p>
<!-- Teraz wynik aktualizuje się na bieżąco -->

❌ Błąd 3 – Użycie zmiennej w TypeScript

❌ Zmienna szablonowa nie działa w .ts

// .ts – to nie zadziała!
zapiszDane(): void {
  // imieInput to zmienna szablonowa – nie istnieje tutaj
  const wartosc = imieInput.value; // ❌ BŁĄD
}

✅ Przekaż wartość jako argument

<!-- .html – przekaż .value do metody -->
<button (click)="zapiszDane(imieInput.value)">
  Zapisz
</button>

// .ts – metoda otrzymuje wartość jako parametr
zapiszDane(wartosc: string): void {
  console.log(wartosc); // ✅ działa
}
✏️

Zadanie – formularz dodawania produktu

Stwórz aplikację z prostym formularzem, która używa zmiennych szablonowych. Klasa komponentu może zawierać tylko metody i tablicę produktów – resztę zrób przez zmienne szablonowe.

Formularz powinien zawierać:

  • Pole tekstowe „Nazwa produktu” z zmienną szablonową #nazwaInput
  • Pole numeryczne „Cena” z zmienną szablonową #cenaInput
  • Przycisk „Dodaj produkt”

Po kliknięciu przycisku:

  • Wywołaj metodę dodajProdukt(nazwa, cena) przekazując wartości pól
  • Metoda dodaje produkt do tablicy w klasie
  • Wyczyść pola formularza (nazwaInput.value = '')

Pod formularzem wyświetl:

  • Podgląd wpisywanej nazwy i ceny na żywo (przez {{ nazwaInput.value }})
  • Listę dodanych produktów (na razie może być w tabelce Bootstrap – @for poznamy w następnym temacie, na razie wystarczy że metoda działa)
Następny temat

W następnym materiale poznamy dyrektywy warunkowe @if i @else – mechanizm wyświetlania różnych fragmentów HTML w zależności od warunków logicznych.