W poprzednim artykule stworzyliśmy nasz pierwszy komponent dla aplikacji – listę to do. Czas dodać do niej zadania! Żeby to zrobić stworzymy komponent pojedynczego zadania na liście.
Wymagania wstępne:
Spisane w formie checklisty (do wydrukowania bądź podglądu/importu jako szablon Nozbe):
Materiały do nauki oraz informacje co i jak znajdziesz we wpisie Tworzymy aplikację webową – krok po kroku – podsumowanie aktualnego statusu & co dalej?
Branch, odpowiadający dzisiejszemu artykułowi: 03-todo-item-component : commit #1, commit #2
Tworzymy komponent pojedynczego zadania na liście
Krok pierwszy:
Wygeneruj nowy komponent korzystając z Angular CLI. Umieść go w folderze todo-list.
Spróbuj zrobić to samodzielnie. A później sprawdź poniższą podpowiedź:
Umieśćmy component na naszej liście:
1 2 |
<h2>{{ list.name }}</h2> <app-todo-item></app-todo-item> |
Na chwilę obecną da to taki efekt:
Świetnie! Wiemy, że działa. No, ale przydałoby się, żeby jeszcze wyglądał jakoś sensownie 😉
Wcześniej wspominałam, że gdybyśmy chcieli stworzyć taki statyczny element to do, mógłby wyglądać następująco:
1 2 3 4 |
<div> <input type="checkbox" name="task1"> <label for="task1">Task #1</label> </div> |
Skopiuj ten kod do pliku todo-item.component.html. Efekt?
Przydałoby się jednak by nazwa elementu nie była zapisana w kodzie na stałe. TodoItem to komponent wizualny i w zasadzie nie powinien interesować się tym, co wyświetla. Ta wiedza powinna przychodzić z góry, najlepiej z miejsca, w którym znajduje się nazwa samej listy.
Istnieją szanse, że zastanawiasz się na tym etapie, że „coś nie halo”. Tworzymy i przechowujemy te dane w różnych miejscach, za chwilę będziemy tworzyć zadania. A gdzie jakiś model? Jakiś ład? Jakiś porządek?
To wszystko przyjdzie z czasem, krok po kroku będziemy zmieniać aplikację.
Ogólnie budowa aplikacji webowej nie polega na tym, że piszemy krok po kroku docelową aplikację. Kod jest ciągle przebudowywany, rozszerzany, zmieniany. W zależności od stawianych przed nim zadań. Nasza aplikacja również będzie się zmieniać. Ale krok po kroku.
Dodajmy pola do naszej listy.
app.component.ts
1 2 3 4 5 6 7 8 |
lists = { todo: { name: 'To do', tasks: [ 'Todo #1' ] } } |
Ponieważ do naszego komponentu todoList przekazujemy całą obiekt lists.todo, nie musimy nic zmieniać w HTML odpowiadającym AppComponent. Możemy po prostu odczytać list.tasks, tak samo jak list.name:
1 2 |
<h2>{{ list.name }}</h2> <app-todo-item [task]="list.tasks[0]"></app-todo-item> |
Przydałaby się jednak współpraca po drugiej stronie. Wiesz czego brakuje w todo-item.component.ts? Jak ma nasłuchiwać na dane wejściowe?
Tak. @Input.
1 |
@Input() task: any; |
A ponieważ mamy nasze zadanie – możemy je wyświetlić:
1 2 3 4 |
<div> <input type="checkbox" name="task1"> <label for="task1">{{ task }}</label> </div> |
Rozszerzmy trochę ilość zadań na liście.
1 2 3 4 5 |
tasks: [ 'Todo #1', 'Todo #2', 'Todo #3' ] |
1 2 3 4 |
<h2>{{ list.name }}</h2> <app-todo-item [task]="list.tasks[0]"></app-todo-item> <app-todo-item [task]="list.tasks[1]"></app-todo-item> <app-todo-item [task]="list.tasks[2]"></app-todo-item> |
Pojawiły się kolejne elementy? Pojawiły.
Mam nadzieję, że już na tym etapie zauważasz, że dokładnie kolejnych w ten sposób… no, chyba do końca nie ma sensu.
Mamy listę. Jak przejść po jej elementach i dla każdego z nich stworzyć odpowiedni komponent?
Oczywiście pętla for. Od zera do długości listy.
Ale nie zwykład pętla for.
Kod po tym etapie zamknęłam w oddzielnym commit’cie. Możesz go znaleźć tutaj. Za chwilę ulegnie sporym zmianom.
*ngFor
Angular oferuje coś takiego jak *ngFor.
*ngFor jest tzw. dyrektywą strukturalną. Jest to typ dyrektywy odpowiedzialnej za strukturę aplikacji (HTML). Dodaje, usuwa albo manipuluje elementami.
Jak rozpoznać dyrektywę strukturalną? Właśnie po gwiazdce * (asterisk).
Jak wykorzystać dyrektywę *ngFor w naszej aplikacji?
1 |
<app-todo-item *ngFor="let task of list.tasks" [task]="task"></app-todo-item> |
Teraz, niezależnie od ilości zadeklarowanych zadań pojawią się one na liście To do.
W tym momencie component listy możemy uznać za zakończony.
1 2 3 4 |
<div> <h2>{{ list.name }}</h2> <app-todo-item *ngFor="let task of list.tasks" [task]="task"></app-todo-item> </div> |
1 2 3 4 5 6 7 8 9 10 11 12 13 |
import { Component, OnInit, Input } from '@angular/core'; @Component({ selector: 'app-todo-list', templateUrl: './todo-list.component.html', styleUrls: ['./todo-list.component.scss'] }) export class TodoListComponent implements OnInit { @Input() list: any; constructor() { } ngOnInit() { } } |
Spełnia wszystkie nasze dotychczasowe oczekiwania.
No, mogłaby wyglądać odrobinę lepiej…
Dlatego w jednym z kolejnych artykułów zobaczymy jak Bootstrap może odmienić jej oblicze 😉 Ale zanim przejdziemy do wyglądu, skupmy się na działaniu.
Przypominam, że kod aplikacji po dzisiejszej lekcji znajdziesz na Github’ie, branch: 03-todo-item-component
Jeśli chcesz podejrzeć same zmiany:
W razie pytań – śmiało dawaj znać w komentarzu lub na naszej Tutorialowej Grupie Wsparcia na Facebooku.
Powodzenia!