1. Czym jest ngClass?
ngClass to dyrektywa Angulara umożliwiająca dynamiczne dodawanie lub usuwanie klas CSS na elementach HTML w zależności od stanu danych lub logiki aplikacji. Jest to bardzo przydatne narzędzie do kontrolowania prezentacji komponentów bezpośrednio z poziomu kodu TypeScript, co zwiększa elastyczność i możliwości dostosowania interfejsu użytkownika.
Przykłady zastosowań:
- Zmiana kolorów elementów w zależności od statusu
- Stylowanie formularzy w zależności od walidacji
- Podświetlanie aktywnych elementów menu
- Motywy jasny/ciemny
- Animacje na podstawie interakcji użytkownika
2. Jak działa ngClass
Dyrektywa ngClass może przyjmować różne formy wejścia:
- String: Jedna klasa lub wiele klas rozdzielonych spacjami
- Array: Tablica nazw klas
- Object: Obiekt, gdzie klucze to nazwy klas, a wartości to wyrażenia logiczne (true/false)
Ważne: Musisz zaimportować CommonModule w komponencie standalone!
import { CommonModule } from '@angular/common';
@Component({
imports: [CommonModule], // Wymagane dla ngClass
// ...
})3.Podstawowy przykład – Status użytkownika
Definicja komponentu
// status.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'app-status',
standalone: true,
imports: [CommonModule],
templateUrl: './status.component.html',
styleUrl: './status.component.css'
})
export class StatusComponent {
userStatus = 'active'; // 'active', 'inactive', 'pending'
changeStatus(newStatus: string) {
this.userStatus = newStatus;
}
}Szablon HTML z użyciem ngClass
<!-- status.component.html -->
<div class="container">
<h2>Status użytkownika</h2>
<!-- Użycie ngClass z obiektem -->
<div [ngClass]="{
'status-active': userStatus === 'active',
'status-inactive': userStatus === 'inactive',
'status-pending': userStatus === 'pending'
}" class="status-badge">
Status: {{ userStatus }}
</div>
<!-- Przyciski do zmiany statusu -->
<button (click)="changeStatus('active')" class="btn btn-success">Aktywny</button>
<button (click)="changeStatus('inactive')" class="btn btn-danger">Nieaktywny</button>
<button (click)="changeStatus('pending')" class="btn btn-warning">Oczekujący</button>
</div>Stylowanie komponentu
/* status.component.css */
.status-badge {
padding: 12px 20px;
border-radius: 25px;
font-weight: bold;
text-align: center;
margin: 20px 0;
transition: all 0.3s ease;
}
.status-active {
background-color: #d4edda;
color: #155724;
border: 2px solid #28a745;
}
.status-inactive {
background-color: #f8d7da;
color: #721c24;
border: 2px solid #dc3545;
}
.status-pending {
background-color: #fff3cd;
color: #856404;
border: 2px solid #ffc107;
}4. Krótkie przykłady zastosowań
Przykład 1: ngClass ze stringiem – motyw
export class ThemeComponent {
currentTheme = 'dark';
toggleTheme() {
this.currentTheme = this.currentTheme === 'dark' ? 'light' : 'dark';
}
}<div [ngClass]="currentTheme" class="theme-container">
<h3>Aktualny motyw: {{ currentTheme }}</h3>
<button (click)="toggleTheme()">Zmień motyw</button>
</div>.theme-container {
padding: 20px;
border-radius: 8px;
transition: all 0.3s ease;
}
.dark {
background-color: #343a40;
color: #ffffff;
}
.light {
background-color: #f8f9fa;
color: #212529;
border: 1px solid #dee2e6;
}Przykład 2: ngClass z tablicą – oceny filmów
export class FilmRatingComponent {
film = {
title: 'Avengers',
rating: 8.4,
isNew: true,
isPopular: true
};
getFilmClasses(): string[] {
const classes = ['film-item'];
if (this.film.rating >= 8.0) classes.push('high-rated');
if (this.film.isNew) classes.push('new-release');
if (this.film.isPopular) classes.push('popular');
return classes;
}
}<div [ngClass]="getFilmClasses()">
<h4>{{ film.title }}</h4>
<p>Ocena: {{ film.rating }}/10</p>
</div>.film-item {
padding: 15px;
border-radius: 8px;
margin: 10px 0;
}
.high-rated { border-left: 5px solid #28a745; }
.new-release { box-shadow: 0 0 10px rgba(0, 123, 255, 0.5); }
.popular { background: linear-gradient(135deg, #fff3cd, #f8f9fa); }Przykład 3: ngClass z obiektem – menu nawigacyjne
export class NavigationComponent {
activeMenuItem = 'home';
setActive(menuItem: string) {
this.activeMenuItem = menuItem;
}
isActive(menuItem: string): boolean {
return this.activeMenuItem === menuItem;
}
}<nav class="navigation">
<a (click)="setActive('home')"
[ngClass]="{'nav-item': true, 'active': isActive('home')}">
Home
</a>
<a (click)="setActive('films')"
[ngClass]="{'nav-item': true, 'active': isActive('films')}">
Filmy
</a>
<a (click)="setActive('contact')"
[ngClass]="{'nav-item': true, 'active': isActive('contact')}">
Kontakt
</a>
</nav>.nav-item {
padding: 10px 15px;
cursor: pointer;
transition: background-color 0.3s;
}
.nav-item:hover {
background-color: #e9ecef;
}
.active {
background-color: #007bff;
color: white;
}Przykład 4: Przycisk z różnymi stanami
export class ButtonStatesComponent {
buttonState = 'normal'; // 'normal', 'loading', 'success', 'error'
simulateAction() {
this.buttonState = 'loading';
setTimeout(() => {
this.buttonState = Math.random() > 0.5 ? 'success' : 'error';
setTimeout(() => {
this.buttonState = 'normal';
}, 2000);
}, 2000);
}
}<button
(click)="simulateAction()"
[disabled]="buttonState === 'loading'"
[ngClass]="{
'btn': true,
'btn-normal': buttonState === 'normal',
'btn-loading': buttonState === 'loading',
'btn-success': buttonState === 'success',
'btn-error': buttonState === 'error'
}">
@if (buttonState === 'loading') {
Ładowanie...
} @else if (buttonState === 'success') {
Sukces!
} @else if (buttonState === 'error') {
Błąd!
} @else {
Kliknij mnie
}
</button>.btn {
padding: 10px 20px;
border: none;
border-radius: 5px;
cursor: pointer;
transition: all 0.3s ease;
}
.btn-normal { background-color: #007bff; color: white; }
.btn-loading { background-color: #ffc107; color: #212529; }
.btn-success { background-color: #28a745; color: white; }
.btn-error { background-color: #dc3545; color: white; }Przykład 5: Lista zadań z priorytetami
export class TaskListComponent {
tasks = [
{ id: 1, name: 'Obejrzeć film', priority: 'low', completed: false },
{ id: 2, name: 'Napisać recenzję', priority: 'high', completed: true },
{ id: 3, name: 'Kupić bilety', priority: 'medium', completed: false }
];
toggleTask(task: any) {
task.completed = !task.completed;
}
}<div class="task-list">
@for (task of tasks; track task.id) {
<div
(click)="toggleTask(task)"
[ngClass]="{
'task-item': true,
'completed': task.completed,
'priority-high': task.priority === 'high',
'priority-medium': task.priority === 'medium',
'priority-low': task.priority === 'low'
}">
{{ task.name }}
</div>
}
</div>.task-item {
padding: 10px;
margin: 5px 0;
border-radius: 5px;
cursor: pointer;
border-left: 4px solid #ddd;
}
.completed {
opacity: 0.6;
text-decoration: line-through;
}
.priority-high { border-left-color: #dc3545; }
.priority-medium { border-left-color: #ffc107; }
.priority-low { border-left-color: #28a745; }5. Ćwiczenia do samodzielnego wykonania
- Karta produktu – różne style w zależności od dostępności i ceny
- System powiadomień – różne kolory dla różnych typów alertów
- Galeria zdjęć – podświetlanie wybranego zdjęcia
- Quiz – kolorowanie odpowiedzi (poprawne/błędne)
- Dashboard pogodowy – różne ikony i kolory dla różnej pogody