Łatwiejszy Routing AngularJS z Angular UI Router

Aczkolwiek AngularJS posiada wbudowany routing, możesz czasami uznać go za ograniczający; framework Angular UI Router może pomóc złagodzić ból. Natywna implementacja routingu AngularJS jest odpowiedzialna za inicjalizację kontrolerów, które pasują do tras aplikacji. Chociaż ta funkcjonalność działa dobrze w podstawowych scenariuszach, w zaawansowanych sytuacjach szybko okazuje się, że natywny routing Angulara:

  • Wymaga ręcznej zmiany ciągów adresów URL w całej bazie kodu, gdy zmienia się adres URL.
  • Wymaga zapamiętania składni trasy verbatim, aby nawigować do strony.
  • Nie oferuje zagnieżdżonych widoków.
  • Nie oferuje nazwanych widoków.
  • Nie pozwala na przekazywanie danych podczas nawigacji.

Jako alternatywa, framework Angular UI Router jest warstwą abstrakcji dla routingu, która charakteryzuje się bardziej deklaratywnym podejściem do nawigacji. Szkielet UI Router wypełnia również niektóre luki w natywnej implementacji, zapewniając zagnieżdżone i nazwane widoki, pozwala na przekazywanie danych między widokami i wiele więcej.

Szkielet Angular UI Router jest warstwą abstrakcji dla routingu, która charakteryzuje się deklaratywnym podejściem do nawigacji

W tym artykule nauczysz się budować prostą aplikację, która używa frameworka UI Router. Po drodze zapoznamy się ze stanami, sposobami rozwiązywania zależności i poznamy różne metody nawigacji.

Zrozumienie stanów

Prawdopodobnie najlepszym sposobem na docenienie problemu, który framework UI Router ma nadzieję rozwiązać, jest rozważenie natury sieci Web. W większości aplikacji, gdy tworzysz odnośnik do strony, definiujesz jawną ścieżkę URL. Na przykład, jeśli chcesz przejść do strony Produkty, możesz mieć URL jak:

Code Sample 1: Version 2 Flexible Container

http://www.example.com/products

W tej sytuacji występują dwa problemy. Pierwszym z nich jest to, że musisz pamiętać dokładną, dosłowną ścieżkę do strony Products za każdym razem, gdy tworzysz łącze. Chociaż podany tutaj przykład może być łatwy do zapamiętania, wiele adresów URL w świecie rzeczywistym nie jest tak łatwych do zapamiętania. Kolejny problem pojawia się, gdy dzieje się coś nieuniknionego i ktoś postanawia zmienić ścieżkę na coś innego. Kiedy adres URL się zmienia, musisz upewnić się, że wszystkie istniejące linki są zaktualizowane, aby wskazywały na nową lokalizację.

Zamiast śledzić ścieżki URL dosłownie, czy nie wolałbyś po prostu powiedzieć aplikacji, aby „przeszła na stronę Produkty”? Pozwalając aplikacji zajmować się nawigacją, pozbywasz się konieczności znajomości dosłownej ścieżki i jesteś chroniony przed zepsutymi linkami spowodowanymi nieuchronnością zmian. Użycie stanów daje taki poziom elastyczności. Stan enkapsuluje lokalizację URL, nazwę stanu, wyspecjalizowane dane dla widoku, identyfikuje sposób na zlokalizowanie lub wygenerowanie widoku, a nawet może ujawnić niestandardowe zdarzenia.

Wprowadzenie Angular UI Router

Angular UI Router jest frameworkiem, który całkowicie zastępuje natywny routing dostępny w AngularJS. UI Router jest bardzo podobny do natywnego routingu AngularJS w tym, że aplikacje składają się z powłoki, która przechowuje placeholder dla dynamicznej zawartości. Rysunek 1 demonstruje, jak powłoka aplikacji hostuje element, który używa dyrektywy ui-view. W miarę jak reguły stanu są oceniane przez framework, zawartość HTML jest renderowana wewnątrz placeholdera.

Rysunek 1: Framework UI Router dodaje zawartość HTML do placeholdera na stronie.

Angular UI Router jest frameworkiem, który całkowicie zastępuje natywny routing dostępny w AngularJS.

Poza renderowaniem zawartości HTML, framework UI Router obsługuje routing URL, możliwość rozwiązywania zależności przed inicjalizacją kontrolerów, nazwane i zagnieżdżone widoki, filtry użytkowe, zdarzenia zmiany stanu i deklaratywne przejścia między stanami.

Przejście między stanami

Istnieje kilka różnych sposobów, których można użyć do przechodzenia między różnymi stanami. Pierwszym sposobem jest dyrektywa ui-sref. Prawdopodobnie znasz atrybut href znacznika HTML anchor (który reprezentuje odwołanie do hipertekstu); podobnie, dyrektywa ui-sref odnosi się do odwołania do stanu. Dyrektywy tej używamy deklarując nazwę stanu z dyrektywą ui-sref zastosowaną do kotwicy. Na przykład:

<a ui-sref="about">About Us</a>

Gdy framework UI Router ocenia tę dyrektywę, kotwica jest przekształcana tak, aby miała odpowiednią wartość URL. Na przykład:

<a ui-sref="about" href="#about">About Us</a>

Zauważ, że element jest aktualizowany, aby zawierał atrybut href z wartością odpowiadającą temu, jak adres URL musi zostać zaktualizowany, aby nawigować do strony About Us. Dyrektywa ui-sref jest dość elastyczna. Obsługuje proste scenariusze, jak również sposoby radzenia sobie z zagnieżdżonymi stanami, a nawet sparametryzowanymi wartościami.

Następnym podejściem do nawigacji pomiędzy stanami jest użycie metody z obiektu $state, która jest dostępna dla kontrolera Angular. W tym kolejnym snippecie można zobaczyć, jak zaimplementowana jest metoda navigate do wywołania $state.go i przejścia aplikacji do stanu about.

angular.module('app') .controller('PageController', );

Obiekt $state jest wstrzykiwany przez framework UI Router i zawiera wiele metod, które pomagają zarządzać i manipulować stanem w aplikacji. Wartość tutaj polega na tym, że mówisz aplikacji aby „poszła” do stanu about i jesteś uwolniony od znajomości dosłownej ścieżki URL do strony.

Pobieranie i instalacja

Istnieje wiele różnych sposobów na uzyskanie dostępu do frameworka UI Router. Możesz pobrać najnowszą wersję bezpośrednio z repozytorium GitHub pod adresem https://github.com/angular-ui/ui-router. Alternatywnie można zainstalować framework za pośrednictwem Bower lub NuGet, a nawet dołączyć łącza CDN do swoich stron; oba te rozwiązania są dostępne pod adresem http://cdnjs.com/libraries/angular-ui-router.

Usługiwanie Angular UI Router

Następnie przedstawimy samouczek demonstrujący, jak zbudować prostą statyczną aplikację opartą na treści przy użyciu frameworka UI Router. Rysunek 2 przedstawia przykładową aplikację strony domowej, którą nauczysz się budować w trakcie czytania tego artykułu. Na tym zrzucie ekranu, możesz zobaczyć powłokę aplikacji i jak zawartość strony domowej jest wstrzykiwana w placeholder za pomocą dyrektywy ui-view.

Rysunek 2: Strona główna i domyślny stan aplikacji

Możesz zmienić stan, aby przejść do strony kontaktowej, jak pokazano na rysunku 3. Mechanizm na stronie kontaktowej wykorzystuje metodę go obiektu $state, przekazując do metody nazwę stanu.

Rysunek 3 : Strona kontaktowa

Kolejny stan jest związany ze stroną listy artykułów, jak widać na rysunku 4. Tutaj tablica z danymi artykułu jest udostępniana widokowi po wstrzyknięciu surowych wartości do kontrolera przez UI Framework. Nawigacja na tej stronie jest ułatwiona dzięki dyrektywie ui-sref, która pozwala deklaratywnie wyrazić stan aplikacji, do którego chcemy nawigować.

Rys. 4: Strona z listą artykułów

Ostatnia strona, zilustrowana na Rys. 5, pokazuje, jak zagnieżdżony stan jest używany w aplikacji.

Rysunek 5 : Strona szczegółów artykułu

Konfiguracja

Aby rozpocząć pracę z frameworkiem UI Router, należy skonfigurować stronę. Pierwszym krokiem jest dodanie nazwy aplikacji do atrybutu ng-app elementu HTML na stronie. Tutaj, nazwa aplikacji to po prostu app.

< html ng-app="app">

Następnie, musisz dodać dyrektywę ui-view do elementu na stronie, aby działała jako placeholder dla zawartości wstrzykiwanej przez framework. W tym przypadku dyrektywa jest dodawana do elementu div.

< div ui-view></div>

Na koniec musisz odwołać się do Angular i Angular UI Router na stronie.

<script src="scripts/lib/angular.min.js"></script><script src="scripts/lib/angular-ui-router.min.js"></script><script src="scripts/app/app.js"></script>

Ten wycinek kodu zawiera również odwołanie do skryptu app.js w folderze script/app, który zawiera kod inicjalizujący aplikację Angular. Proces inicjalizacji jest miejscem, gdzie większość konfiguracji i interfejsu z frameworkiem UI Router jest zaimplementowana.

Definiowanie stanów

Jak wspomniano wcześniej, podstawą frameworka UI Router jest użycie różnych stanów w aplikacji. Poprzez dostęp do każdego z tych stanów, aplikacja może nawigować do lub odtworzyć się w zależności od okoliczności w cyklu życia aplikacji. Poniższa sekcja demonstruje jak zdefiniować stany dla aplikacji; cały kod jest zaimplementowany w pliku app.js. Każda sekcja jest analizowana oddzielnie, ale jeśli chciałbyś zobaczyć pełny skrypt inicjalizacyjny, zajrzyj do Listingu 1.

Pierwszym krokiem jest skonfigurowanie UI Routera w Twojej aplikacji AngularJS. Po nadaniu nazwy modułowi, masz możliwość zarejestrowania frameworka UI Router jako zależności aplikacji poprzez dodanie literału ui.router do tablicy zależności. (Zwróć uwagę, jak komentarz oznacza placeholder dla kodu w kolejnym snippecie.)

angular.module('app', ) .config(/* add configuration here */);

Po zdefiniowaniu modułu i zarejestrowaniu zależności, aplikacja jest ustawiona na uruchomienie anonimowej funkcji, która wykonuje się podczas fazy konfiguracji aplikacji. Tutaj, istnieje kilka zasobów wstrzykniętych do funkcji, które są istotne dla frameworka UI Router.

 

Obiekt $stateProvider posiada metodę state, która pozwala na zdefiniowanie granularnych stanów aplikacji, które mogą lub nie mogą pokrywać się ze zmianami w URL. Obiekt $urlRouterProvider jest obiektem, który daje kontrolę nad tym, jak zarządzana i obserwowana jest lokalizacja przeglądarki. W kontekście UI Routera, $urlRouterProvider jest używany do pomocy w zdefiniowaniu scenariusza nawigacji typu catch-all. Każdy z tych obiektów jest omówiony bardziej szczegółowo w kolejnych wycinkach kodu. (Ponownie, zauważ, że kolejne fragmenty kodu są umieszczane w miejscu komentarza placeholder w poprzednim fragmencie.)

Każdy stan aplikacji jest definiowany poprzez podanie nazwy i poinformowanie frameworka, gdzie ma znaleźć znaczniki dla danego widoku. Tutaj, stan home jest definiowany przez podanie adresu url oraz wartości właściwości templateUrl.

$stateProvider .state('home', { url: '/', templateUrl: '/partials/home.html' })

To mówi aplikacji, aby załadowała zawartość pliku home.html do obiektu placeholder ui-view, gdy użytkownik przejdzie do korzenia aplikacji. W tym miejscu zaczynasz dostrzegać jedną z zalet routingu stanocentrycznego. Jeśli z jakiegoś powodu chcielibyśmy, aby adres URL dla stanu home wskazywał na /home zamiast na lokalizację samego korzenia (/), zmiana ta musiałaby zajść tylko tutaj, w konfiguracji. Ten stan pomija wszelkie zaawansowane ustawienia i ładuje statyczną stronę do przeglądarki. Może się zdarzyć, że będziemy chcieli powiązać konkretny kontroler z tym stanem.

Stan contact jest ustawiony tak, aby załadować znacznik strony contact.html do ui-view placeholder. Poza wykonaniem podstawowej operacji replace, kontroler ContactsController jest również skojarzony z widokiem na poziomie elementu DOM, w którym znajduje się dyrektywa ui-view.

 .state('contact', { url: '/contact', templateUrl: '/partials/contact.html', controller: 'ContactController', })

Jak pokazano na rysunku 3, strona Contact zawiera przycisk umożliwiający nawigację do strony Articles. Nawigacja odbywa się w kontrolerze ContactsController i demonstruje, jak połączyć kontroler z widokiem ładowanym na żądanie przez framework UI Router.

Stan strony Artykuły posuwa konfigurację o krok dalej poprzez dodanie wartości do obiektu, który rozwiązuje wszelkie skonfigurowane wartości zdefiniowane w obiekcie. Celem tego stanu jest renderowanie listy dostępnych artykułów na stronie. Stan ten jest skonfigurowany tak, aby informacje o artykułach były dostępne dla kontrolera zanim zostanie on zainicjowany. W poniższym snippecie, stan definiuje wartość w obiekcie resolve.

 .state('articles', { url: '/articles', templateUrl: '/partials/articles.html', resolve: { articles: 'ArticlesService' }, controller: 'ArticlesController' })

W tym przypadku, właściwość articles wskazuje na łańcuch ArticlesService. Kiedy przekazujesz łańcuch znaków jako wartość do właściwości resolve, framework kontaktuje się z usługą zarejestrowaną pod tą samą nazwą i rozwiązuje usługę do jej ostatecznej wartości. W tym przypadku, ArticlesService zwraca obietnicę, więc powiązany z nią kontroler nie jest inicjowany dopóki obietnica usługi nie zostanie rozwiązana i końcowy obiekt nie będzie dostępny jako wstrzykiwalna wartość dla kontrolera. Implementacja usługi ArticlesService jest dostępna na listingu 3.

Po wyświetleniu użytkownikowi listy artykułów, jak pokazano na rysunku 4, użytkownik może wybrać artykuł i zagłębić się w zawartość witryny. Akcja ta jest reprezentowana przez stan zagnieżdżony. Zauważ, że nazwa stanu zawiera kropkę (.) pomiędzy articles i article, aby zaznaczyć relację rodzic-dziecko pomiędzy stanami.

 .state('articles.article', { url: '/:pageName', templateUrl: function ($stateParams) { return '/partials/articles/' + $stateParams.pageName + '.html'; } });

W tym przypadku zastosowano specjalną regułę dotyczącą sposobu obliczania właściwości url. Ponieważ jest to widok zagnieżdżony (jak wskazuje kropka w nazwie stanu), wartość właściwości url będzie konkatenowana z wartością url stanu nadrzędnego. Oznacza to, że wszystkie pasujące stany będą miały adres URL, który zaczyna się od /articles, a następnie zawiera nazwę strony artykułu.

Występowanie dwukropka (:) wskazuje na parametr URL. Dzięki wprowadzeniu parametru do adresu URL, definicja stanu staje się na tyle elastyczna, że może obsługiwać dowolny stan, który pasuje do relacji ze swoim stanem nadrzędnym. Stan ten posiada również funkcję, która jest uruchamiana w celu zwrócenia wartości dla templateUrl. Użycie funkcji w tym miejscu daje możliwość wykorzystania parametrów zdefiniowanych w adresie url stanu. Jakąkolwiek nazwę nadamy parametrowi we właściwości url, odpowiada ona nazwie właściwości obiektu $stateParams. Dlatego ten stan pobiera nazwę pageName przekazaną w adresie URL, aby użyć jej w funkcji templateUrl w celu uzyskania dostępu do poszczególnych plików zawartości, które są ostatecznie wstrzykiwane do elementu hostującego dyrektywę ui-view.

Jest to ostatni stan zdefiniowany w aplikacji. Aby zobaczyć, jak wszystkie stany są zaimplementowane w rzeczywistym skrypcie inicjalizacyjnym, zapoznaj się z Listingiem 1.

Ostatnie polecenie wymagane do wydania aplikacji dotyczy tego, co zrobić, jeśli użytkownik spróbuje wejść na adres URL, który nie został zdefiniowany w metodzie configure. Poprzez użycie metody otherwise z obiektu $urlRouterProvider, wszelkie nierozpoznane adresy URL są odrzucane, a aplikacja jest przekierowywana do domyślnej lokalizacji. W tym przypadku aplikacja jest skonfigurowana do przekierowania na główny adres URL, jeśli podany adres URL nie pasuje do zdefiniowanego stanu.

$urlRouterProvider.otherwise('/');

Teraz, mając zdefiniowany każdy stan aplikacji, możesz zacząć zwracać uwagę na budowanie usługi ArticlesService.

Resolving Data with the Articles Service

Konfiguracja dla stanu artykułu zawiera wartość opcji resolve. Ten obiekt jest skonfigurowany tak, aby miał wartość łańcuchową ArticlesService ustawioną na właściwość articles (patrz Listing 1 dla kontekstu). Dostarczenie łańcucha do obiektu resolve mówi frameworkowi, aby zlokalizował usługę zarejestrowaną w aplikacji i rozwiązał ją do jej ostatecznej wartości. Usługa ArticlesService jest zaimplementowana tak, aby zwracać obietnicę.

angular.module('app').factory('ArticlesService', ); return deferred.promise; }]);

Tutaj usługa używa usługi $q do utworzenia obietnicy zwracającej tablicę. W tym przypadku wartości są zakodowane na sztywno, ale w rzeczywistym kontekście może być potrzebny dostęp do zdalnego serwera w celu dostarczenia danych. W każdym przypadku, usługa musi być w pełni rozwiązana, zanim router przekaże wykonanie do powiązanego z nią kontrolera. Dlatego też, gdy wywoływany jest stan artykułu, ostatecznie kontroler otrzymuje tablicę obiektów artykułu jako zależność.

Używanie rozwiązanych danych w ArticlesController

Jedną z zalet używania frameworka UI Router jest możliwość wymuszenia separacji obaw. Ponieważ stan articles implementuje obiekt resolve, surowa tablica artykułów jest wstrzykiwana do kontrolera.

angular.module('app') .controller('ArticlesController', );

Takie podejście jest lepsze niż wymaganie, aby ArticlesController „wiedział” o ArticlesService, ponieważ o wiele łatwiej jest wyśmiewać surową tablicę obiektów do celów testowych, zamiast zajmować się wyśmiewaniem samej usługi. Pełną implementację kontrolerów aplikacji można znaleźć na Listingu 2.

Renderowanie listy artykułów

Teraz, gdy aplikacja przeszła do stanu artykułu, a kontroler ma tablicę artykułów ustawioną w zakres, widok jest gotowy do renderowania. Widok Artykuły składa się z dwóch części. Pierwsza z nich to kolejny div placeholder, który wykorzystuje dyrektywę ui-view w celu utworzenia widoku zagnieżdżonego. Druga część to nieuporządkowana lista różnych artykułów dostępnych na stronie. Skonstruowanie widoku w ten sposób pozwala na klikanie na różne tytuły artykułów, podczas gdy lista artykułów pozostaje na stronie. (Jest to możliwe dzięki temu, że zawartość strony jest ładowana do widoku ui-view na poziomie artykułu, podczas gdy strona jako całość jest renderowana w widoku ui-view w powłoce aplikacji. Pełna implementacja powłoki aplikacji jest dostępna na listingu 4.

Następujący fragment kodu demonstruje, w jaki sposób widok articles implementuje widok zagnieżdżony.

<div ui-view> <!-- default content goes here --></div>...<ul class="list-group"> <li class="list-group-item" c> <a ui-sref="articles.article({pageName: '{{article.pageName}}'})"> {{article.title}}</a> </li></ul>

Istnieją trzy sposoby, w jakie ten znacznik wykorzystuje framework UI Router. Po pierwsze, element div wykorzystuje dyrektywę ui-view jako placeholder, i jak mówi komentarz, można przekazać domyślną zawartość do renderowania w placeholder, zanim jakakolwiek zawartość zostanie wyrenderowana przez framework. Listing 5 demonstruje, jak statyczna wiadomość jest używana jako zawartość placeholder na stronie, zanim jakakolwiek zawartość zostanie załadowana do widoku.

Po drugie, element anchor ma zastosowaną dyrektywę ui-sref. To sygnalizuje ramom UI Router, aby przetwarzały to łącze w kontekście ram i ostatecznie renderują standardową wartość href, która pasuje do adresu URL dla zadeklarowanego stanu w oparciu o ustawienia zdefiniowane w konfiguracji aplikacji (patrz Listing 1).

Trzeci sposób użycia frameworka polega na tym, że wartość dyrektywy ui-sref akceptuje wyrażenie generujące poprawną wartość URL dla zagnieżdżonego stanu. Tutaj, hash jest przekazywany do hierarchii zagnieżdżonego stanu (w tym przypadku articles.article), gdzie wartość dla pageName jest powiązana z przychodzącym artykułem’s pageName. Kiedy framework UI Router ocenia to wyrażenie, odpowiednia wartość URL jest generowana dla każdego artykułu, który pasuje do zdefiniowanych reguł stanu.

Więcej abstrakcyjnej nawigacji

Ostatnim kontrolerem do zaimplementowania jest ContactController, który używa metody go parametru stanu do nawigacji aplikacji do nowego stanu.

app.controller('ContactController', );

Tutaj, po prostu wywołując metodę go z nazwą stanu, twój kontroler zajmuje się tylko deklarowaniem stanu, do którego chcesz przejść, zamiast próbować śledzić konkretny schemat routingu w aplikacji.

Wniosek

Ale AngularJS jest wyposażony w funkcjonalną implementację routingu, możesz szybko zdać sobie sprawę z zalet używania opartego na stanach frameworka routingu dla nietrywialnych aplikacji. Framework UI Router zapewnia łatwe sposoby definiowania stanów, rozwiązywania zależności i korzystania z zagnieżdżonych widoków. Aby uzyskać jeszcze więcej informacji na temat możliwości tego frameworka, odwiedź dom projektu na GitHubie pod adresem https://github.com/angular-ui/ui-router/.

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.