Zadanie101
Zadanie 101: Dynamiczne Komponenty Formularzy (Input, Select, Checkbox)
Wstęp
Kontynuując temat reużywalności (rozpoczęty w Zadaniu 100), zajmiemy się tworzeniem dynamicznych elementów formularzy. Formularze są nieodłączną częścią aplikacji webowych, a standardowe inputy HTML często wymagają powtarzania tego samego kodu (etykiety, klasy walidacyjne, style Bootstrap).
W tym zadaniu stworzymy zestaw komponentów formularzowych, które będą konfigurowalne przez parametry @Input.
Część 1: Komponent Input (custom-input)
Krok 1: Generowanie komponentu
ng generate component custom-input
Krok 2: Definiowanie parametrów
Edytuj custom-input.component.ts. Chcemy przekazywać:
label(tekst etykiety)type(typ inputa: 'text', 'password', 'email', 'number')placeholder(tekst pomocniczy)id(unikalny identyfikator, ważny dla accessibility)
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-custom-input',
standalone: true,
templateUrl: './custom-input.component.html',
styleUrl: './custom-input.component.scss' // Plik SCSS może być pusty, jeśli używamy tylko klas Bootstrapa
})
export class CustomInputComponent {
@Input() label: string = '';
@Input() type: string = 'text';
@Input() placeholder: string = '';
@Input() id: string = '';
}
Krok 3: Szablon HTML
Edytuj custom-input.component.html:
<div class="mb-3">
<label [for]="id" class="form-label">{{ label }}</label>
<input
[type]="type"
class="form-control"
[id]="id"
[placeholder]="placeholder">
</div>
Część 2: Komponent Select (custom-select)
Krok 1: Generowanie komponentu
ng generate component custom-select
Krok 2: Logika i parametry
Selektor potrzebuje listy opcji. Przyjmijmy, że każda opcja to prosty string lub obiekt (dla uproszczenia zaczniemy od stringów).
import { Component, Input } from '@angular/core';
import { CommonModule } from '@angular/common'; // Potrzebne dla dyrektywy *ngFor
@Component({
selector: 'app-custom-select',
standalone: true,
imports: [CommonModule],
templateUrl: './custom-select.component.html',
styleUrl: './custom-select.component.scss'
})
export class CustomSelectComponent {
@Input() label: string = '';
@Input() id: string = '';
@Input() options: string[] = [];
}
Krok 3: Szablon HTML
<div class="mb-3">
<label [for]="id" class="form-label">{{ label }}</label>
<select class="form-select" [id]="id">
<option selected disabled>Wybierz opcję...</option>
<option *ngFor="let opt of options" [value]="opt">{{ opt }}</option>
</select>
</div>
Część 3: Komponent Checkbox (custom-checkbox)
Krok 1: Generowanie
ng generate component custom-checkbox
Krok 2: Kod TypeScript
import { Component, Input } from '@angular/core';
@Component({
selector: 'app-custom-checkbox',
standalone: true,
templateUrl: './custom-checkbox.component.html',
styleUrl: './custom-checkbox.component.scss'
})
export class CustomCheckboxComponent {
@Input() label: string = '';
@Input() id: string = '';
@Input() checked: boolean = false;
}
Krok 3: Szablon HTML
Struktura checkboxa w Bootstrapie jest specyficzna:
<div class="form-check mb-3">
<input class="form-check-input" type="checkbox" [id]="id" [checked]="checked">
<label class="form-check-label" [for]="id">
{{ label }}
</label>
</div>
Część 4: Budowa formularza rejestracji
Teraz użyjmy naszych "klocków" w app.component.ts (lub innym komponencie rodzicu).
Krok 1: Dane w komponencie rodzica
W app.component.ts przygotuj dane dla selecta:
export class AppComponent {
roles = ['Administrator', 'Moderator', 'Użytkownik'];
}
Pamiętaj o zaimportowaniu stworzonych komponentów w tablicy imports.
Krok 2: Składanie widoku
W app.component.html:
<div class="container mt-5" style="max-width: 500px;">
<h2>Formularz Rejestracji</h2>
<form>
<!-- Dynamiczne Inputy -->
<app-custom-input
label="Nazwa użytkownika"
id="username"
placeholder="Wpisz login...">
</app-custom-input>
<app-custom-input
label="Email"
type="email"
id="email"
placeholder="[email protected]">
</app-custom-input>
<app-custom-input
label="Hasło"
type="password"
id="pass"
placeholder="********">
</app-custom-input>
<!-- Dynamiczny Select -->
<app-custom-select
label="Rola w systemie"
id="role"
[options]="roles">
</app-custom-select>
<!-- Dynamiczny Checkbox -->
<app-custom-checkbox
label="Akceptuję regulamin serwisu"
id="terms">
</app-custom-checkbox>
<!-- Przycisk z Zadania 100 (jeśli masz) lub zwykły -->
<button type="submit" class="btn btn-primary w-100 mt-2">Zarejestruj</button>
</form>
</div>
Zadanie domowe (dla chętnych)
- Spraw, aby komponenty faktycznie zwracały wartość do rodzica (użyj
@Output()iEventEmitterlub spróbuj zaimplementowaćControlValueAccessordla obsługiReactive Forms). - Dodaj parametr
@Input() errorMessage: string, który wyświetli czerwony komunikat pod polem, jeśli wystąpi błąd walidacji.