ANGULAR – canDeactivate Guard

Czołem! W dzisiejszym artykule pokażę, jak skorzystać z guarda o nazwie CanDeactivate.

Scenariusz, który rozpatrzę:

  • użytkownik wypełnia widok z formularzem, np. edytuje dane usera
  • w przypadku próby zmiany routa (np. kliknięcie w menu) pokaże się modal, w którym user zostanie zapytany, czy chce opuścić widok bez zachowania zmian
  • modal pokaże się w przypadku, kiedy formularz jest dirty
  • submit button również będzie przekierowywać routa, ale nie będzie nigdy wywoływać modala

Z czego skorzystam:

  • modal z biblioteki ng-bootstrap
  • klasa canDeactivate

Efekt:

No to wio ;)!

ngBootstrap modal

Najpierw musimy pobrać bibliotekę ngBootstrap. Proces instalacji w linku poniżej:

https://ng-bootstrap.github.io/#/getting-started

Po szybkiej instalacji poprzez NPM, importujemy moduł NgbModule w pliku app.module.ts

Ok, mamy teraz w zanadrzu dostęp do gotowego modala, którego pokażemy użytkownikowi.

CanDeactivate i CanActivate Guard

Warto wiedzieć, jaka jest różnica pomiędzy poniższymi Guardami:

  • CanDeactivate Guard – sprawdza, czy mamy pozwolenie na opuszczenie danego routa (route to np. localhost:4200/myNgApp/users/12)
  • CanActivate Guard – sprawdza, czy mamy pozwolenie na wejście do danego routa

Brzmi banalnie. Skupmy się na pierwszym.

CanDeactivate Guard jest interfejsem z jedną metodą – canDeactivate, która może zwrócić:

Jeśli Guard zwróci true – opuszczamy widok, jeśli false – zostajemy na danym widoku.

Oraz przyjmuje cztery parametry (czwarty opcjonalny):

Parametr component, wskazuje na klasę komponentu, w którym będziemy będziemy chcieli skorzystać z Guarda. Jeśli chcesz poczytać o pozostałych parametrach, musisz zajrzeć do dokumentacji, nie są tematem artykułu.

Skoro już wiemy, do czego służy interfejs CanDeactivate, to możemy przejść do kodowania.

CanDeactivate Guard – implementacja

Modala pytającego, chcę wywołać w następującym przypadku:

  • User form jest „dirty”, czyli user zaczął coś robić z formularzem
  • wywołanie zmiany routa nie zostało wywołane kliknięciem buttona submit (użyję do tego flagi)

Zaczniemy od zakodowania klasy Guarda:

Nie będę wdawać się w szczegóły biblioteki RxJS i czym jest Subject, bo jest to bardziej złożony temat. Korzystam z Subjectu, aby móc emitować wartość true lub false i nasłuchiwać na wysłaną wartość:

Następnie przygotowuję dwie metody:

  • discard() – zostanie wywołana, jeśli w modalu użytkownik kliknie „discard” button, czyli stwierdzi, że chce opuścić widok bez zachowania zmian. Wyemituję w niej wartość true, aby móc zmienić routa
  • keep() – metodę keep chce wywołać w 3 przypadkach:

1. Użytkownik kliknie na tło modala

2. Użytkownik zamknie modal poprzez close button „x”

3. Użytkownik kliknie keep w modalu

Zatem w keep wyemituję false, aby zostać w danym roucie (widoku).

Następnie w metodzie canDeactivate, dodaję warunek po spełnieniu którego, ma się pokazać modal:

Subject jest jednocześnie Observerem i Observablem. W tym miejscu nasłuchuję na wyemitowaną wartość i ją zwracam. Będzie true – użytkownik opuści widok, jak false – to zostanie w widoku z formularzem.

Teraz musimy zarejestrować naszego guarda w Providers w odpowiednim module i dodać go do wybranej ścieżki w routingu:

App.routing.module.ts:

Teraz czas wstrzyknąć guarda do klasy komponentu.

Klasa komponentu z detalami usera

Kod klasy, z pominięciem nieistotnych linii:

Kroki istotne do wywołania modala:

  1. Wstrzykujemy klasę z Guardem do konstruktora
  2. Przygotowuję pole discardModalFlag, które pozwoli nam nie wołać Guarda w przypadku kliknięcia submit buttona, który również zmienia routa
  3. W metodzie openDiscardModal(),  discardModalRef.result zwraca mi promise. Resolve dotyczy akcji closeModal (kliknięcie close button), natomiast Reject dotyczy akcji dismissModal (np. kliknięcie w tło modala, lub guzika ESCAPE). W obu przypadkach chcę zostać na widoku, więc wywołam 2x metodę Keep()
  4. Metodę discardChanges() przypisuję do buttona „discard” w modalu

Jeśli chcesz poznać szczegóły działania modala z biblioteki ngBootstrap, to zapraszam do dokumentacji, a jeśli nie, to musi starczyć Ci powyższe info;)

Tadam! to wszystko. Kodu HTML nie będę wklejać, możesz go obejrzeć w repo.

Całość kodu w poniższym repozytorium:

https://github.com/angularlove/ng-guards/tree/master/src/app

PODSUMOWANIE

Genialna sprawa ten Guard! nie trzeba ręcznie obserwować wszystkich możliwych elementów, które uruchamiają routing. Guard sam wie, że próba zmiany routa została wywołana. Dodatkowo można to zrobić bardziej generycznie i mieć jednego canDeactivate Guarda do obsługi powtarzających się formularzy (a z modala zrobić reużywalny komponent). Z pewnością istnieje wiele scenariuszy, w których przyda się can Deactivate guard.

 

 

 

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *