Witam po dwutygodniowej, świąteczno-sylwestrowej przerwie! Wracam do Ciebie z porcją wiedzy kodu i wiedzy.
Z dzisiejszego wpisu dowiesz się, w jaki sposób wykorzystać MaterialDesign do zarządzania oknami dialogowymi Twojej aplikacji. W międzyczasie zrealizujemy dwa kolejne wymagania:
- As a user I should be able to preview entered data after „Submit” button press
- As a user I should be able to press „Confirm” or „Cancel” in the Confirmation Window.
- When „Confirm” button is pressed the new transaction should appear at the top of the transactions’ history.
Całą dokumentację znajdziesz tutaj.
Po pierwsze, primo
Żeby skorzystać z dobrodziejstw MaterialDesign
musisz stworzyć komponent, który otworzysz jako okno modalne. Z racji tego, że komponent ten związany jest z modułem dodawania transakcji właśnie tam go stworzyłem (/addtransaction/confirmation-dialog
). Kod jest banalnie prosty:
import { Component, Inject } from "@angular/core"; import { MAT_DIALOG_DATA } from "@angular/material/dialog"; import { Transaction } from "../../../model/transaction"; @Component({ selector: "app-confirmation-dialog", templateUrl: "./confirmation-dialog.component.html" }) export class ConfirmationDialogComponent { constructor( @Inject(MAT_DIALOG_DATA) public data: Transaction, private readonly transactionRepoService: TransactionRepositoryService ) {} public confirm(): void { this.transactionRepoService.addTransaction(this.data); } }
Konstruktor przyjmuje dane w postaci transakcji, która właśnie się odbywa. Za chwilę zobaczysz, w jaki sposób ten komponent nakarmić tą transakcją. Chwilowo jednak nie przejmuj się tym.
Dodatkowo komponent udostępnia publiczną metodę confirm()
. Musisz ją zawołać w momencie kiedy użytkownik kliknie guzik potwierdzający poprawność danych (patrz -> szablon). Po potwierdzeniu transakcja powinna zostać zatwierdzona w systemie. Z tego powodu wstrzyknąłem TransactionRepositoryService
właśnie do tego komponentu. Funkcjonalność dodającą przelew załatwia metoda addTransaction()
, którą tutaj wywołuję (linijka przeniesiona z TransactionFormComponent
).
Po drugie, primo
Szablon komponentu:
<h2 mat-dialog-title>Confirm transaction</h2> <mat-dialog-content> <div>{{data.account.name}}</div> <div>{{data.amount}}</div> </mat-dialog-content> <mat-dialog-actions> <button mat-button mat-dialog-close>Cancel</button> <button (click)="confirm()" mat-button [mat-dialog-close]="true">Confirm</button> </mat-dialog-actions>
I już widzisz gdzie metoda confirm()
się wywoła. Szablon wykorzystuje mat-design
i składa się z trzech głównych części:
<mat-dialog-title></mat-dialog-title>
– nic innego jak tytuł okienka<mat-dialog-content></mat-dialog-content>
– zawartość okna, czyli dane które wyświetla<mat-dialog-actions></mat-dialog-actions>
– akcje, które może wykonać użytkownik na tym okienku. W naszym przypadku możliwe są dwie opcje: anulowanie transakcji i zamknięcie okna lub jej potwierdzenie.- Dyrektywa
mat-button
powinna nadać odpowiedni wygląd przyciskowi (oczywiście dopiero po zaimportowaniu styliMaterialDesign
) - Dyrektywa
mat-dialog-close
definiuje zachowanie okienka po wciśnięciu danego guzika. Z ustawioną wartością na true zamknie okno po wykonaniu akcji.
- Dyrektywa
A po trzecie primo, ultimo!
Nowy komponent jest częścią modułu dodawania transakcji, dlatego właśnie tam go deklaruję:
@NgModule({ imports: [ ReactiveFormsModule, MatDialogModule, BrowserAnimationsModule ], declarations: [TransactionFormComponent, ConfirmationDialogComponent], exports: [TransactionFormComponent], entryComponents: [ConfirmationDialogComponent] }) export class AddTransactionModule {}
Żeby okienko ładnie się wyświetlało importuję BrowserAnimationsModule
.
Zwróć uwagę na tablicę entryComponents[]
. Komponent okienka wrzucam właśnie do niej. W skrócie rzecz ujmując każdy komponent, do którego nie odwołujesz się bezpośrednio w danym module za pomocą jego selektora (czyli w żadnym szablonie) powinien zostać zadeklarowany właśnie tutaj. Jeżeli chcesz więcej informacji zapraszam do dokumentacji.
Modyfikuję troszkę konstruktor komponentu formularza:
export class TransactionFormComponent { … constructor(private fb: FormBuilder, public dialog: MatDialog) { this.createForm(); } … }
Usunąłem TransactionRepositoryService
(przeniesione do komponentu okienka) i wstrzyknąłem MatDialog
. Już wcześniej zaimportowałem MatDialogModule
w AddTransactionModule
. Całość przygotowana do obsługi i zarządzania oknami dialogowymi.
Połącz wszystko, żeby działało…
No dobra to teraz jak to spiąć, żeby okno się pokazało z danymi wprowadzonymi w formularzu? Po pierwsze otwórzmy okno po zatwierdzeniu danych formularza:
public onSubmit(): void { const toAccountNumber = this.transactionForm.value.toAccount; const toAccountName = this.transactionForm.value.toAccountName; const amount = this.transactionForm.value.amount; const currentDate = new Date(); const bankAccount = new BankAccount(toAccountName, toAccountNumber); const transaction = new Transaction( bankAccount, amount, currentDate.getDate() ); this.openDialog(transaction); }
Teraz, zamiast wołać od razu
this.repositoryService.addTransaction(transaction)
jak robiliśmy dotychczas, wywołuję nową metodę this.openDialog(transaction)
. Metoda ta wygląda tak:
private openDialog(transaction: Transaction): void { const dialogRef = this.dialog.open(ConfirmationDialogComponent, { data: transaction }); dialogRef.afterClosed().subscribe(result => { this.clearForm(); }); }
I właśnie w tym miejscu mówisz ConfirmationDialogComponent
co jest jego danymi ({data: transaction}
). Dodatkowo zapisuję się na event zamknięcia okienka po to, żeby wyczyścić formularz.
Tyle! Kod źródłowy znajdziesz tutaj.
P.S. Idea #start_angular to pomysł zapoznania Cię ze światem aplikacji webowych i programowania. Jeżeli chcesz otrzymywać zadanie do wykonania po przeczytaniu każdego wpisu, listę zrealizowanych tematów oraz powiadomienia o nowych wpisach, dołącz proszę do mojego mailingu.
Super, czekaliśmy z niecierpliwością 😉