Deși AngularJS este livrat cu rutare încorporată, este posibil ca uneori să vi se pară limitat; cadrul Angular UI Router vă poate ajuta să ușurați durerea. Implementarea nativă de rutare AngularJS este responsabilă pentru inițializarea controlorilor care se potrivesc cu rutele aplicației. Deși această funcționalitate funcționează bine în scenariile de bază, în situații avansate, descoperiți rapid că rutarea nativă Angular:
- Vă obligă să schimbați manual șirurile de URL-uri în întreaga bază de cod atunci când se schimbă un URL.
- Vă obligă să rețineți textual sintaxa rutei pentru a naviga către o pagină.
- Nu oferă vizualizări imbricate.
- Nu oferă vizualizări cu nume.
- Nu vă permite să transferați date în timpul navigării.
Ca alternativă, cadrul Angular UI Router este un strat de abstractizare pentru rutare care prezintă o abordare mai declarativă a navigării. Cadrul UI Router umple, de asemenea, unele dintre lacunele implementării native prin furnizarea de vizualizări imbricate și numite, vă permite să treceți date între vizualizări și multe altele.
Cadrul Angular UI Router este un strat de abstractizare pentru rutare care prezintă o abordare declarativă a navigării
În acest articol, veți învăța să construiți o aplicație simplă care utilizează cadrul UI Router. Pe parcurs, vă veți familiariza cu stările, cu modul de rezolvare a dependențelor și veți învăța diverse metode de navigare.
- Înțelegerea stărilor
- Introducing Angular UI Router
- Navigația între stări
- Descărcare și instalare
- Utilizarea Angular UI Router
- Configurare
- Definirea stărilor
- Rezolvarea datelor cu Articles Service
- Utilizarea datelor rezolvate în ArticlesController
- Rendarea listei de articole
- Mai multă navigare abstractă
- Concluzie
Înțelegerea stărilor
Poate că cel mai bun mod de a aprecia problema pe care cadrul UI Router speră să o rezolve este de a lua în considerare natura Web-ului. În majoritatea aplicațiilor, atunci când creați un link către o pagină, definiți o cale URL explicită. De exemplu, dacă ați dori să navigați către pagina Products a site-ului dumneavoastră, ați putea avea un URL de tipul:
Code Sample 1: Version 2 Flexible Container
http://www.example.com/products
Există două probleme în această situație. Prima este că trebuie să vă amintiți calea literală exactă către pagina Produse de fiecare dată când stabiliți o legătură. Deși exemplul dat aici poate fi ușor de reținut, multe URL-uri din lumea reală nu sunt atât de ușor de memorat. Întâlniți următoarea problemă atunci când se întâmplă inevitabilul și cineva decide să schimbe calea de acces în altceva. Când un URL se schimbă, atunci trebuie să vă asigurați că toate legăturile existente sunt actualizate pentru a indica noua locație.
În loc să trebuiască să țineți evidența textual a căilor URL, nu ați prefera mai degrabă să spuneți pur și simplu aplicației să „meargă la pagina Produse”? Permițând aplicației să se preocupe singură de navigare, sunteți scutit de necesitatea de a cunoaște calea literală și sunteți protejat de legăturile rupte cauzate de inevitabilitatea schimbării. Utilizarea stărilor vă oferă acest nivel de flexibilitate. O stare încapsulează o locație URL, numele stării, date specializate pentru vizualizare, identifică o modalitate de a localiza sau de a genera vizualizarea și poate chiar expune evenimente personalizate.
Introducing Angular UI Router
Angular UI Router este un cadru care înlocuiește în întregime rutarea nativă disponibilă în AngularJS. UI Router este foarte asemănător cu rutarea nativă din AngularJS în sensul că aplicațiile sunt compuse dintr-un shell care deține un spațiu rezervat pentru conținutul dinamic. Figura 1 demonstrează modul în care shell-ul aplicației găzduiește un element care utilizează directiva ui-view. Pe măsură ce regulile de stare sunt evaluate în cadrul, conținutul HTML este redat în interiorul placeholder-ului.
Angular UI Router este un cadru care înlocuiește în totalitate rutarea nativă disponibilă în AngularJS.
În afară de redarea conținutului HTML, cadrul UI Router suportă rutarea URL-urilor, capacitatea de a rezolva dependențele înainte ca controlorii să fie inițializați, vizualizări numite și imbricate, filtre de utilitate, evenimente de schimbare a stării și tranziții declarative între stări.
Există câteva moduri diferite pe care le puteți folosi pentru a vă deplasa între diferite stări. Prima modalitate este directiva ui-sref. Probabil că sunteți familiarizat cu atributul href al etichetei de ancorare HTML (care reprezintă o referință de hipertext); în mod similar, directiva ui-sref se referă la o referință de stare. Folosiți această directivă prin declararea unui nume de stare cu directiva ui-sref aplicată unei ancore. De exemplu:
<a ui-sref="about">About Us</a>
În timp ce cadrul UI Router evaluează această directivă, ancora este transformată pentru a avea valoarea URL corespunzătoare. De exemplu:
<a ui-sref="about" href="#about">About Us</a>
Observați că elementul este actualizat pentru a include un atribut href cu o valoare corespunzătoare modului în care trebuie actualizat URL-ul pentru a naviga către pagina Despre noi. Directiva ui-sref este destul de flexibilă. Suportă atât scenarii simple, cât și modalități de a trata stări imbricate și chiar valori parametrizate.
Următoarea abordare pentru navigarea între stări este de a utiliza o metodă din obiectul $state care este disponibilă pentru un controler Angular. În următorul fragment, puteți vedea cum este implementată metoda navigate pentru a apela $state.go și pentru a face tranziția aplicației la starea about.
angular.module('app') .controller('PageController', );
Obiectul $state este injectat de cadrul UI Router și include o serie de metode pentru a vă ajuta să gestionați și să manipulați starea în aplicație. Valoarea aici este că îi spuneți aplicației să „meargă” la starea about și sunteți scutit de cunoașterea căii URL literale către pagină.
Descărcare și instalare
Există mai multe moduri diferite prin care puteți obține acces la cadrul UI Router. Puteți descărca cea mai recentă versiune direct din depozitul GitHub la https://github.com/angular-ui/ui-router. Alternativ, puteți instala cadrul prin Bower sau NuGet sau chiar să includeți link-uri CDN în paginile dumneavoastră; ambele sunt disponibile la http://cdnjs.com/libraries/angular-ui-router.
Utilizarea Angular UI Router
Ceea ce urmează este un tutorial care demonstrează cum să construiți o aplicație simplă bazată pe conținut static folosind cadrul UI Router. Figura 2 ilustrează exemplul de aplicație pentru pagina de pornire pe care învățați să o construiți pe măsură ce citiți acest articol. Din această captură de ecran, puteți vedea învelișul aplicației și modul în care conținutul paginii de pornire este injectat în spațiul rezervat cu ajutorul directivei ui-view.
Puteți schimba starea pentru a naviga către pagina de contact, așa cum se arată în figura 3. Mecanismul de pe pagina de contact utilizează metoda go a obiectului $state, trecând un nume de stare în metodă.
Următoarea stare este asociată cu pagina de listă a articolului, așa cum se vede în Figura 4. Aici, o matrice de date ale articolului este pusă la dispoziția vizualizării după ce valorile brute au fost injectate în controler de către UI Framework. Navigarea pe această pagină este facilitată prin intermediul directivei ui-sref, care permite exprimarea declarativă a stării aplicației către care se dorește să se navigheze.
Pagina finală, ilustrată în figura 5, arată modul în care este utilizată o stare imbricata în aplicație.
Configurare
Pentru a începe să lucrați cu cadrul UI Router, trebuie să configurați pagina. Primul pas este să adăugați numele aplicației în atributul ng-app al elementului HTML din pagină. Aici, numele aplicației este pur și simplu app.
< html ng-app="app">
În continuare, trebuie să adăugați directiva ui-view la un element al paginii pentru a acționa ca un spațiu rezervat pentru conținutul injectat de framework. În acest caz, directiva este adăugată la un element div.
< div ui-view></div>
În cele din urmă, trebuie să faceți referire atât la Angular, cât și la Angular UI Router pe pagină.
<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>
Acest fragment de cod include, de asemenea, o referință la scriptul app.js din folderul script/app care conține codul de inițializare a aplicației Angular. Procesul de inițializare este cel în care este implementată cea mai mare parte a configurării și a interfeței cu cadrul UI Router.
Definirea stărilor
După cum s-a menționat anterior, baza cadrului UI Router este utilizarea diferitelor stări într-o aplicație. Prin accesarea fiecăreia dintre aceste stări, aplicația poate naviga sau se poate reconstitui în funcție de circumstanțele din cadrul ciclului de viață al aplicației. Următoarea secțiune demonstrează cum se definesc stările pentru aplicație; tot codul este implementat în fișierul app.js. Fiecare secțiune este examinată în mod izolat, dar dacă doriți să vedeți întregul script de inițializare, vă rugăm să consultați Listarea 1.
Primul pas este să configurați UI Router în aplicația AngularJS. După numirea modulului, aveți posibilitatea de a înregistra cadrul UI Router ca dependență a aplicației prin adăugarea literalului ui.router în matricea de dependențe. (Observați cum comentariul denotă un spațiu rezervat pentru codul dintr-un fragment ulterior.)
angular.module('app', ) .config(/* add configuration here */);
După ce modulul este definit și dependențele sunt înregistrate, aplicația este configurată pentru a rula o funcție anonimă care se execută în timpul fazei de configurare a aplicației. Aici, există câteva resurse injectate în funcție care sunt relevante pentru cadrul UI Router.
Obiectul $stateProvider dispune de metoda state care vă permite să definiți stări granulare ale aplicației care pot coincide sau nu cu modificări ale URL-ului. Obiectul $urlRouterProvider este un obiect care vă oferă control asupra modului în care este gestionată și observată locația browserului. În contextul UI Router, $urlRouterProvider este utilizat pentru a ajuta la definirea unui scenariu de navigare de tip catch-all. Fiecare dintre aceste obiecte este discutat mai detaliat în următoarele fragmente de cod. (Din nou, rețineți că fragmentele de cod ulterioare sunt plasate în poziția comentariului de tip placeholder din fragmentul anterior.)
Care stare a aplicației este definită prin furnizarea unui nume și prin indicarea cadrului unde să găsească marcajul pentru vizualizare. Aici, starea home este definită prin furnizarea locației rădăcină pentru url și a unei valori pentru proprietatea templateUrl.
$stateProvider .state('home', { url: '/', templateUrl: '/partials/home.html' })
Aceasta îi spune aplicației să încarce conținutul fișierului home.html în placeholder-ul ui-view atunci când utilizatorul navighează la rădăcina aplicației. Aici, începeți să vedeți unul dintre avantajele de a avea o rutare centrată pe stare. Dacă, dintr-un motiv oarecare, ați dori ca URL-ul pentru starea home să fie îndreptat către /home în loc de locația rădăcină goală (/), această modificare ar trebui să se facă doar aici, în configurație. Această stare renunță la orice configurare avansată și încarcă o pagină statică în browser. Pot exista și alte momente în care doriți să asociați un controler specific cu starea.
Starea contact este configurată pentru a încărca marcajul paginii contact.html în locul ui-view. Dincolo de efectuarea unei operații de înlocuire de bază, ContactsController este, de asemenea, asociat vizualizării cu domeniul de cuprindere la nivelul elementului DOM care găzduiește directiva ui-view.
.state('contact', { url: '/contact', templateUrl: '/partials/contact.html', controller: 'ContactController', })
Așa cum se arată în figura 3, pagina Contact include un buton pentru a naviga la pagina Articole. Navigarea se face în ContactsController și demonstrează modul de conectare a unui controler la o vizualizare încărcată la cerere de către cadrul UI Router.
Statul paginii Articole duce configurarea cu un pas mai departe prin adăugarea de valori în obiectul care rezolvă orice valori configurate definite în obiect. Scopul acestei stări este de a reda o listă a articolelor disponibile pe site. Această stare este configurată pentru ca informațiile despre articole să fie disponibile pentru controler înainte ca acesta să fie instanțiat. În fragmentul următor, starea definește o valoare în obiectul de rezolvare.
.state('articles', { url: '/articles', templateUrl: '/partials/articles.html', resolve: { articles: 'ArticlesService' }, controller: 'ArticlesController' })
În acest caz, proprietatea articles indică șirul ArticlesService. Atunci când treceți un șir de caractere ca valoare în proprietatea resolve, cadrul contactează un serviciu înregistrat sub același nume și rezolvă serviciul până la valoarea sa finală. În acest caz, ArticlesService returnează o promisiune, astfel încât controlerul asociat nu este instanțiat până când promisiunea serviciului nu este rezolvată, iar obiectul final este disponibil ca valoare injectabilă pentru controler. Implementarea pentru ArticlesService este disponibilă în lista 3.
După ce lista de articole este redată utilizatorului, așa cum este descrisă în figura 4, utilizatorul poate selecta un articol și poate pătrunde în conținutul site-ului. Această acțiune este reprezentată de o stare imbricata. Observați cum numele stării include un punct (.) între articles și article pentru a denota o relație părinte-copil între stări.
.state('articles.article', { url: '/:pageName', templateUrl: function ($stateParams) { return '/partials/articles/' + $stateParams.pageName + '.html'; } });
Aici, există o regulă specială aplicată la modul în care este evaluată proprietatea url. Deoarece aceasta este o vizualizare imbricata (așa cum este indicat de punctul din numele statului), valoarea proprietății url va fi concatenată cu valoarea url a statului părinte. Aceasta înseamnă că orice stare care se potrivește va avea un URL care începe cu /articles și apoi include numele paginii articolului.
Prezența celor două puncte (:) indică un parametru URL. Prin introducerea unui parametru în URL, definiția stării devine suficient de flexibilă pentru a gestiona orice stare care se potrivește cu relația pe care o are cu starea sa părinte. Această stare prezintă, de asemenea, o funcție care este executată pentru a returna valoarea pentru templateUrl. Utilizarea unei funcții aici vă oferă posibilitatea de a utiliza parametrii definiți în adresa URL a stării. Indiferent de numele pe care îl dați parametrului din proprietatea url se potrivește cu numele proprietății din obiectul $stateParams. Prin urmare, acest stat preia PageName trecut în URL pentru a fi utilizat în funcția templateUrl pentru a accesa fișiere individuale de conținut care sunt în cele din urmă injectate în elementul care găzduiește directiva ui-view.
Aceasta este ultima stare definită în aplicație. Pentru a vedea cum sunt implementate toate stările în scriptul de inițializare propriu-zis, consultați lista 1.
Ultima comandă necesară pentru a da aplicației este ce trebuie să facă în cazul în care utilizatorul încearcă să acceseze un URL care nu este definit în metoda configure. Prin utilizarea metodei altfel din obiectul $urlRouterProvider, orice URL nerecunoscut este eliminat și aplicația este redirecționată către o locație implicită. În acest caz, aplicația este configurată pentru a redirecționa către URL-ul rădăcină dacă URL-ul dat nu se potrivește cu o stare definită.
$urlRouterProvider.otherwise('/');
Acum, cu fiecare stare a aplicației definită, puteți începe să vă îndreptați atenția către construirea ArticlesService.
Rezolvarea datelor cu Articles Service
Configurarea pentru starea articolului include o valoare pentru opțiunea resolve. Acest obiect este configurat pentru a avea o valoare de șir de caractere ArticlesService setată la proprietatea articles (a se vedea lista 1 pentru context). Furnizarea unui șir de caractere pentru obiectul resolve îi spune cadrului să localizeze un serviciu înregistrat în aplicație și să rezolve serviciul până la valoarea sa finală. ArticlesService este implementat pentru a returna o promisiune.
angular.module('app').factory('ArticlesService', ); return deferred.promise; }]);
Aici, serviciul utilizează serviciul $q pentru a crea o promisiune pentru a returna o matrice. În acest caz, valorile sunt codificate dur, dar într-un context din lumea reală, este posibil să fie nevoie să accesați un server la distanță pentru a furniza datele. În orice caz, serviciul trebuie să fie complet rezolvat înainte ca cadrul routerului să transmită execuția către controlerul asociat. Prin urmare, pe măsură ce starea articolului este invocată, în cele din urmă controlerului i se trece o matrice de obiecte articol ca dependență.
Utilizarea datelor rezolvate în ArticlesController
Unul dintre avantajele utilizării cadrului UI Router este capacitatea de a impune separarea preocupărilor. Deoarece starea articolelor implementează un obiect de rezolvare, matricea brută de articole este injectată în controler.
angular.module('app') .controller('ArticlesController', );
Această abordare este superioară solicitării ca ArticlesController să „știe” despre ArticlesService, deoarece este mult mai ușor să ne batem joc de o matrice brută de obiecte în scopuri de testare decât să ne ocupăm de bătaia de joc a serviciului în sine. Implementarea completă pentru controlorii aplicației se găsește în Lista 2.
Rendarea listei de articole
Acum că aplicația a navigat în starea articolului și controlorul are matricea de articole rezolvată stabilită în domeniul de aplicare, vizualizarea este acum pregătită pentru a fi redată. Vizualizarea articolelor este alcătuită din două părți. Prima este un alt div placeholder care utilizează directiva ui-view pentru a crea o vizualizare imbricata. A doua parte este o listă neordonată a diferitelor articole disponibile pe site. Construirea vizualizării în acest fel vă permite să faceți clic pe diferite titluri de articole, în timp ce lista de articole rămâne pe pagină. (Puteți vedea un exemplu în acest sens în figura 5.) Acest lucru este posibil deoarece conținutul paginii este încărcat în ui-view la nivel de articol, în timp ce pagina ca întreg este redată în ui-view în shell-ul aplicației. Implementarea completă a cochiliei aplicației este disponibilă în Listarea 4.
Următorul fragment de cod demonstrează modul în care vizualizarea articolelor implementează o vizualizare imbricata.
<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>
Există trei moduri în care acest marcaj utilizează cadrul UI Router. În primul rând, elementul div utilizează directiva ui-view ca un placeholder și, așa cum se menționează în comentariu, puteți trece un conținut implicit pentru a fi redat în placeholder înainte ca orice conținut să fie redat de către cadru. Listarea 5 demonstrează modul în care un mesaj static este utilizat ca conținut de tip placeholder pe pagină înainte ca orice conținut să fie încărcat în vizualizare.
În al doilea rând, elementului anchor i se aplică directiva ui-sref. Aceasta semnalează cadrului UI Router să proceseze această legătură în contextul cadrului și, în cele din urmă, redă o valoare href standard care se potrivește cu URL-ul pentru starea declarată, pe baza setărilor definite în configurația aplicației (a se vedea lista 1).
Cel de-al treilea mod în care este utilizat cadrul este că valoarea directivei ui-sref acceptă o expresie pentru a genera valoarea URL corectă pentru o stare imbricata. Aici, un hash este trecut în ierarhia stării imbricate (în acest caz articles.article), unde valoarea pentru pageName este legată de pageName al articolului care intră. Când cadrul UI Router evaluează această expresie, este generată o valoare URL corespunzătoare pentru fiecare articol care se potrivește cu regulile de stare definite.
Ultimul controler de implementat este ContactController, care utilizează metoda go a parametrului de stare pentru a naviga aplicația într-o nouă stare.
app.controller('ContactController', );
În acest caz, prin simpla apelare a metodei go cu un nume de stare, controlerul dumneavoastră este preocupat doar de declararea stării în care doriți să treceți, în loc să încerce să țină evidența schemei concrete de rutare din aplicație.
Concluzie
Deși AngularJS vine echipat cu o implementare funcțională de rutare, vă puteți da seama rapid de avantajele utilizării unui cadru de rutare bazat pe stare pentru aplicații non-triviale. Cadrul UI Router vă oferă modalități simple de a defini stări, de a rezolva dependențele și de a utiliza vizualizările imbricate. Pentru și mai multe informații despre ceea ce poate face cadrul, asigurați-vă că vizitați pagina principală a proiectului pe GitHub la https://github.com/angular-ui/ui-router/.