AngularJS angula

background image
background image

Tytuł oryginału: AngularJS

Tłumaczenie: Robert Górczyński

ISBN: 978-83-246-9990-2

© 2014 Helion S.A.

Authorized Polish translation of the English edition AngularJS, ISBN 9781449344856
© 2013 Brad Green and Shyam Seshadri.

This translation is published and sold by permission of O’Reilly Media, Inc., which owns or
controls all rights to publish and sell the same.

All rights reserved. No part of this book may be reproduced or transmitted in any form or by
any means, electronic or mechanical, including photocopying, recording or by any
information storage retrieval system, without permission from the Publisher.

Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu
niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą
kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym,
magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji.

Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź
towarowymi ich właścicieli.

Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce
informacje były kompletne i rzetelne. Nie bierze jednak żadnej odpowiedzialności ani
za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych
lub autorskich. Wydawnictwo HELION nie ponosi również żadnej odpowiedzialności
za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce.

Wydawnictwo HELION
ul. Kościuszki 1c, 44-100 GLIWICE
tel. 32 231 22 19, 32 230 98 63
e-mail: helion@helion.pl
WWW: http://helion.pl (księgarnia internetowa, katalog książek)

Pliki z przykładami omawianymi w książce można znaleźć pod adresem:
ftp://ftp.helion.pl/przyklady/angula.zip

Drogi Czytelniku!
Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres
http://helion.pl/user/opinie/angula
Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję.

Printed in Poland.

Kup książkę

Poleć książkę

Oceń książkę

Księgarnia internetowa

Lubię to! » Nasza społeczność

background image

3

Spis treļci

Wprowadzenie ...........................................................................................7

Konwencje zastosowane w ksiñĔce 8
UĔycie przykäadowych kodów

8

Podziökowania 9

Rozdziaĥ 1. Wprowadzenie do AngularJS ................................................11

Koncepcje 12
Przykäad — koszyk na zakupy

18

Co dalej?

21

Rozdziaĥ 2. Anatomia aplikacji AngularJS ...............................................23

Wywoäanie AngularJS

23

Architektura MVC

24

Szablony i doäñczanie danych

27

Organizacja zaleĔnoĈci za pomocñ moduäów 51
Formatowanie danych za pomocñ filtrów

55

Zmiana widoków za pomocñ tras i usäugi $location

57

Komunikacja z serwerem

61

UĔycie dyrektyw do zmiany elementów drzewa DOM

63

Weryfikacja danych wejĈciowych uĔytkownika 65
Co dalej?

67

Rozdziaĥ 3. Programowanie w AngularJS ...............................................69

Organizacja projektu

70

Narzödzia 73
Uruchamianie aplikacji

75

Testowanie w AngularJS

76

Testy jednostkowe

79

Kup książkę

Poleć książkę

background image

4

_ Spis

treļci

Testy typu E2E/integracji

80

Kompilacja 82
Inne wspaniaäe narzödzia 84
Narzödzie Yeoman — optymalizacja sposobu pracy

88

Integracja AngularJS i RequireJS

92

Rozdziaĥ 4. Analiza aplikacji AngularJS .................................................101

Aplikacja 101
Relacje miödzy modelem, kontrolerem i szablonem

102

Kontrolery, dyrektywy i usäugi 105
Testy 122

Rozdziaĥ 5. Komunikacja z serwerami .................................................. 129

Komunikacja za pomocñ usäugi $http

129

Testy jednostkowe

135

Praca z zasobami RESTful

137

Usäuga $q i obietnica

143

Przechwycenie odpowiedzi

145

Kwestie bezpieczeþstwa 146
XSRF 147

Rozdziaĥ 6. Dyrektywy ........................................................................... 149

Dyrektywy i weryfikacja kodu HTML

149

Ogólny opis API

150

Co dalej?

170

Rozdziaĥ 7. Inne kwestie .........................................................................171

Usäuga $location

171

Metody moduäu AngularJS

178

Komunikacja miödzy zasiögami

za pomocñ $on, $emit i $broadcast

182

Ciasteczka 184
Internacjonalizacja i lokalizacja

185

Oczyszczanie kodu HTML i moduä Sanitize

188

Kup książkę

Poleć książkę

background image

Spis

treļci

_

5

Rozdziaĥ 8. Ļciéga i podpowiedzi ...........................................................191

Opakowanie kontrolki jQuery datepicker

191

Lista klubów sportowych — filtrowanie i komunikacja

196

Przekazywanie plików w aplikacji AngularJS

201

UĔycie biblioteki Socket.IO

204

Prosta usäuga stronicowania

207

Praca z serwerami i logowaniem

210

Podsumowanie 214

Skorowidz ............................................................................................... 216

Kup książkę

Poleć książkę

background image

6

_ Spis

treļci

Kup książkę

Poleć książkę

background image

101

ROZDZIAĤ 4.

Analiza aplikacji AngularJS

W rozdziale 2. przedstawiono pewne najczöĈciej uĔywane funkcje framewor-

ka AngularJS, natomiast w rozdziale 3. zajöliĈmy siö zagadnieniami zwiñ-
zanymi ze sposobem prowadzenia prac programistycznych. Zamiast konty-
nuowaè wñtek i podobnie szczegóäowo omawiaè poszczególne funkcje,
w tym rozdziale przejdziemy do maäej, rzeczywistej aplikacji. Na jej pod-
stawie dowiesz siö, jak poäñczyè ze sobñ omówione dotñd fragmenty caäoĈci
i utworzyè rzeczywistñ, dziaäajñcñ aplikacjö.

Zamiast od razu przedstawiaè caäñ aplikacjö, bödziemy jñ poznawaè w ma-

äych czöĈciach, omawiaè interesujñce zagadnienia zwiñzane z danym frag-
mentem i tym samym powoli budowaè kompletnñ aplikacjö, która bödzie
gotowa, zanim ukoþczysz lekturö rozdziaäu.

Aplikacja

GutHub to prosta aplikacja przeznaczona do zarzñdzania przepisami kuli-
narnymi. Zostaäa zaprojektowana w taki sposób, aby przechowywaè przepi-
sy kulinarne i jednoczeĈnie pokazywaè róĔne interesujñce aspekty aplikacji
AngularJS. Oto cechy charakteryzujñce tworzonñ przez nas aplikacjö:

x

ma ukäad skäadajñcy siö z dwóch kolumn;

x

pasek nawigacyjny znajduje siö po lewej stronie;

x

pozwala na dodawanie nowych przepisów kulinarnych;

x

umoĔliwia przeglñdanie istniejñcych przepisów kulinarnych.

Widok gäówny aplikacji znajduje siö po prawej stronie. W zaleĔnoĈci od
adresu URL ulega ona zmianie i wyĈwietla listö przepisów kulinarnych,

Kup książkę

Poleć książkę

background image

102 _

Rozdziaĥ 4. Analiza aplikacji AngularJS

szczegóäy dotyczñce konkretnego przepisu lub edytowalny formularz po-
zwalajñcy na dodanie nowego bñdĒ na edycjö istniejñcego. Uruchomionñ
aplikacjö pokazano na rysunku 4.1.

Rysunek 4.1. GutHub, czyli prosta aplikacja przeznaczona do zarzñdzania przepisami
kulinarnymi

Caäa aplikacja jest dostöpna w repozytorium GitHub na stronie: https://github.
com/shyamseshadri/angularjs-book/tree/master/chapter4

.

Relacje miýdzy modelem,
kontrolerem i szablonem

Zanim przejdziemy do omawiania aplikacji, zatrzymajmy siö na chwilö
i zastanówmy, jak trzy fragmenty aplikacji wspóädziaäajñ ze sobñ oraz jak
powinniĈmy je traktowaè.

Model

jest istotñ aplikacji. Powtórz to zdanie kilkakrotnie. Dziaäanie caäej

aplikacji opiera siö na modelu, od którego zaleĔñ: wyĈwietlany widok, dane
wyĈwietlane przez widok, zapisywane informacje i dosäownie wszystko.
Warto wiöc poĈwiöciè nieco czasu i dokäadnie przemyĈleè model — jakie
wäaĈciwoĈci powinien mieè obiekt modelu, jak bödzie pobierany z serwera,
jak bödzie zapisywany i tak dalej. Ze wzglödu na to, Ĕe uaktualnienie wido-
ku nastöpuje automatycznie dziöki uĔyciu wiñzania danych, uwagö naleĔy
skoncentrowaè na modelu.

Kup książkę

Poleć książkę

background image

Relacje miýdzy modelem, kontrolerem i szablonem

_ 103

Kontroler

zawiera logikö biznesowñ i okreĈla miödzy innymi: jak bödzie po-

bierany model, jakie bödñ rodzaje operacji przeprowadzanych na modelu, ja-
kich informacji widok potrzebuje z modelu, a takĔe jak przeksztaäciè model,
aby uzyskaè potrzebne dane. Ponadto przeprowadzanie weryfikacji, wy-

konywanie wywoäaþ do serwera, umieszczanie odpowiednich danych w wi-
doku oraz wäaĈciwie wszystko inne powiñzane z wymienionymi dziaäania-
mi to równieĔ aktywnoĈè definiowana w kontrolerze.

I na koniec szablon okreĈla sposób prezentacji modelu oraz interakcji uĔyt-
kownika z aplikacjñ. Zadania wykonywane przez szablon powinny byè ogra-
niczone do wymienionych poniĔej:

x

wyĈwietlanie modelu;

x

definiowanie sposobów, na jakie uĔytkownik moĔe korzystaè z aplikacji
— klikniöcia, pola danych wejĈciowych i tak dalej;

x

nadawanie stylu aplikacji oraz okreĈlanie, jak i kiedy pewne elementy
majñ byè wyĈwietlane — pokazywanie lub ukrywanie i tak dalej;

x

filtrowanie i formatowanie danych (zarówno wejĈciowych, jak i wyj-

Ĉciowych).

Trzeba pamiötaè, Ĕe szablon w AngularJS niekoniecznie jest widokiem
w architekturze MVC (model – widok – kontroler). Zamiast tego widok jest
skompilowanñ wersjñ wykonywanego szablonu, rodzajem poäñczenia sza-
blonu i modelu.

W szablonie nie naleĔy umieszczaè Ĕadnego rodzaju logiki biznesowej
ani definiowaè zachowania — tego rodzaju dane powinny znajdowaè siö

w kontrolerze. Zachowanie prostoty szablonów pozwala na wäaĈciwñ sepa-
racjö obowiñzków, a ponadto na przetestowanie wiökszoĈci kodu za po-
mocñ jedynie testów jednostkowych. Szablony powinny byè testowane za
pomocñ testów scenariuszy.

W tym miejscu mógäbyĈ zapytaè: gdzie naleĔy umieszczaè polecenia od-
powiedzialne za modyfikacje obiektowego modelu dokumentu? Operacje
na elementach drzewa DOM nie powinny byè definiowane w kontrolerach

lub szablonach. Najlepszym miejscem dla nich sñ dyrektywy AngularJS,
choè czasami wspomniane operacje mogñ byè stosowane za pomocñ usäug,
co pozwala na unikniöcie powielania kodu. Przykäad takiego rozwiñzania
w aplikacji GutHub równieĔ zostanie zaprezentowany i omówiony.

Bez zbödnych ceregieli przechodzimy wiöc do modelu.

Kup książkę

Poleć książkę

background image

104 _

Rozdziaĥ 4. Analiza aplikacji AngularJS

Model

W omawianej aplikacji staramy siö zachowaè maksymalnñ prostotö modelu

— bödñ to po prostu przepisy kulinarne. Wspomniane przepisy to jedyny

obiekt modelu w caäej aplikacji. Wszystkie pozostaäe komponenty zostanñ

zbudowane wokóä modelu.
KaĔdy przepis skäada siö z nastöpujñcych wäaĈciwoĈci:

x

identyfikator, jeĈli przepis zostaä zapisany na serwerze,

x

nazwa,

x

krótki opis,

x

sposób przygotowania,

x

informacje o ewentualnym wyróĔnieniu przepisu,

x

tablica skäadników podanych w postaci nazwy, iloĈci i jednostki miary.

I to tyle, model jest niezwykle prosty. Pozostaäe komponenty aplikacji utwo-

rzymy na podstawie wymienionego modelu. PoniĔej przedstawiono przy-

käadowy przepis kulinarny w formacie JSON (przepis ten zostaä pokazany

na rysunku 4.1 we wczeĈniejszej czöĈci rozdziaäu):

{
"id": "1",

"title": "Ciasteczka",

"description": "Wyborne, chrupiÈce na zewnÈtrz, ciÈgliwe" +
" w Ărodku i ociekajÈce pysznÈ czekoladÈ " +

"ciasteczka. Najlepsze w swoim rodzaju.",

"ingredients": [

{
"amount": "1",

"amountUnits": "opakowanie",

"ingredientName": "Chips Ahoy"

}
],

"instructions": "1. Kup opakowanie Chips Ahoy\n" +

"2. Podgrzej ciasteczka w piekarniku\n" +

"3. Rozsmakuj siÚ w ciepïych ciasteczkach\n" +
"4. Z innego ěródïa naucz siÚ, jak wypiekaÊ wyborne ciasteczka"

}

W celu zachowania prostoty przykäadu nie bödziemy zajmowaè siö serwe-

rem, z którego przepisy kulinarne sñ pobierane lub w którym sñ zapisy-

wane. Kod serwera znajduje siö w repozytorium w serwisie GitHub, a do

jego uruchomienia säuĔy polecenie

node web-server.js

, które trzeba wydaè

z poziomu podstawowego katalogu aplikacji GutHub. Przechodzimy teraz

do znacznie bardziej skomplikowanych funkcji interfejsu uĔytkownika, jakie

moĔna utworzyè na postawie naszego prostego modelu.

Kup książkę

Poleć książkę

background image

Kontrolery, dyrektywy i usĥugi

_ 105

Kontrolery, dyrektywy i usĥugi

Wreszcie moĔemy zajñè siö ciekawszymi aspektami tworzonej przez nas

aplikacji. W pierwszej kolejnoĈci spojrzymy na kod dyrektyw i usäug i po-
wiemy sobie nieco o sposobie jego dziaäania. Nastöpnie przejdziemy do
wielu kontrolerów niezbödnych do zapewnienia prawidäowego dziaäania
tworzonej aplikacji.

Usĥugi

PoniĔej przedstawiono kod Ēródäowy usäug.

// Plik: app/scripts/services/services.js.
var services = angular.module('guthub.services', ['ngResource']);

services.factory('Recipe', ['$resource', function($resource) {
return $resource('/recipes/:id', {id: '@id'});
}]);

services.factory('MultiRecipeLoader', ['Recipe', '$q', function(Recipe, $q) {
return function() {
var delay = $q.defer();
Recipe.query(function(recipes) {
delay.resolve(recipes);
}, function() {
delay.reject('Nie moĝna pobraÊ przepisów kulinarnych.');
});
return delay.promise;
};
}]);

services.factory('RecipeLoader', ['Recipe', '$route', '$q', function(Recipe,
$route, $q) {
return function() {
var delay = $q.defer();
Recipe.get({id: $route.current.params.recipeId}, function(recipe) {
delay.resolve(recipe);
}, function() {
delay.reject('Nie moĝna pobraÊ przepisu ' + $route.current.params.recipeId);
});
return delay.promise;
};
}]);

Najpierw zajmiemy siö usäugami. Nie jest to nasze pierwsze spotkanie
z usäugami — zetknöliĈmy siö z nimi juĔ w rozdziale 2. Tutaj zostanñ omó-
wione nieco dokäadniej.

W przedstawionym pliku znajdujñ siö trzy usäugi AngularJS.

Kup książkę

Poleć książkę

background image

106 _

Rozdziaĥ 4. Analiza aplikacji AngularJS

Istnieje usäuga przepisu kulinarnego, która zwraca tak zwany AngularJS
Resource. Jest to zasób RESTful prowadzñcy do serwera RESTful. Wspo-
mniany zasób hermetyzuje dziaäajñcñ na niskim poziomie usäugö

$http

, a tym

samym programista musi utworzyè jedynie kod odpowiedzialny za pracö

z obiektami.

Za pomocñ tylko pojedynczego wiersza kodu (

return $resource

) oraz oczywi-

Ĉcie zaleĔnoĈci w module

guthub.services

obiekt

Recipe

moĔe byè uĔyty jako

argument w dowolnym kontrolerze — zostanie wówczas wstrzykniöty do
wskazanego kontrolera. Co wiöcej, kaĔdy obiekt

Recipe

ma wbudowane

wymienione poniĔej metody:

x

Recipe.get()

,

x

Recipe.save()

,

x

Recipe.query()

,

x

Recipe.remove()

,

x

Recipe.delete()

.

JeĔeli zamierzasz uĔyè metody Recipe.delete() i chcesz zapewniè
dziaäanie aplikacji w przeglñdarce Internet Explorer, wtedy mu-

sisz uĔyè wywoäania w postaci Recipe['delete'](). Wynika to

z faktu, Ĕe delete jest säowem kluczowym w przeglñdarce In-
ternet Explorer.

Z wymienionych powyĔej metod wszystkie poza

query()

dziaäajñ z poje-

dynczym przepisem kulinarnym. Natomiast wartoĈciñ zwrotnñ metody

query()

jest domyĈlnie tablica przepisów kulinarnych.

Wiersz kodu deklarujñcy zasób (

return $resource

) wykonuje równieĔ kilka

innych uĔytecznych zadaþ.

1.

Zwróè uwagö na

:id

w adresie URL wskazanym dla zasobu RESTful.

Wspomniany identyfikator oznacza, Ĕe w trakcie wykonywania dowol-
nego zapytania (na przykäad za pomocñ

Recipe.get()

), jeĈli przekaĔesz

obiekt wraz z wäaĈciwoĈciñ

id

, wówczas jej wartoĈè zostanie umiesz-

czona na koþcu adresu URL.
Oznacza to, Ĕe wywoäanie

Recipe.get({id: 15})

faktycznie bödzie wy-

woäaniem do /recipe/15.

2.

MógäbyĈ zapytaè w tym miejscu: co z drugim obiektem, na przykäad

{id:

@id}

? Wiersz kodu jest wart tysiñca säów objaĈnienia, wiöc przejdĒmy

od razu do odpowiedniego przykäadu.

Kup książkę

Poleć książkę

background image

Kontrolery, dyrektywy i usĥugi

_ 107

Przyjmujemy zaäoĔenie, Ĕe dostöpny jest obiekt

Recipe

zawierajñcy

wszystkie niezbödne informacje, miödzy innymi wartoĈè

id

.

Wspomniany obiekt moĔna zapisaè za pomocñ poniĔszego fragmentu

kodu:

// PrzyjĊto zaáoĪenie, Īe obiekt existingRecipeObj ma wszystkie niezbĊdne wáaĞciwoĞci,
// w tym id (na przykáad o wartoĞci 13).
var recipe = new Recipe(existingRecipeObj);
recipe.$save();

Przedstawiony kod spowoduje wykonanie Ĕñdania

POST

do /recipe/13.

Fragment

@id

powoduje pobranie wartoĈci wäaĈciwoĈci

id

obiektu i uĔy-

cie jej jako parametru

id

. Takie rozwiñzanie przyjöto dla wygody — po-

zwala ono zaoszczödziè kilka wierszy kodu.

W pliku apps/scripts/services/services.js istniejñ jeszcze dwie inne usäugi.

Obie zaliczajñ siö do komponentów wczytujñcych: pierwsza (

RecipeLoader

)

wczytuje pojedynczy przepis, natomiast druga (

MultiRecipeLoader

) jest prze-

znaczona do wczytywania wszystkich przepisów kulinarnych. Wymienio-

ne usäugi sñ uĔywane podczas konfiguracji tras, a sposób dziaäania tych

usäug jest bardzo podobny i zostaä przedstawiony poniĔej.

1.

Utworzenie obiektu wstrzymanego

$q

(jest to rodzaj obietnicy frameworka

AngularJS stosowanej w celu äñczenia funkcji asynchronicznych).

2.

Wykonanie wywoäania do serwera.

3.

OkreĈlenie obiektu wstrzymanego, gdy serwer zwraca wartoĈè.

4.

Zwrot obietnicy, która bödzie uĔywana przez mechanizm routingu fra-

meworka AngularJS.

Obietnice frameworka AngularJS

Obietnica to interfejs przeznaczony do pracy z obiektami, które sñ zwra-

cane lub bödñ wypeänione w przyszäoĈci (w zasadzie sñ to akcje asyn-

chroniczne). Ogólnie rzecz biorñc, na obietnicö skäada siö obiekt oraz

funkcja

then()

.

Aby zobaczyè zalety obietnic, spójrzmy na przykäad, w którym konieczne

jest pobranie profilu uĔytkownika:

var currentProfile = null;

var username = 'dowolnaNazwa';

fetchServerConfig(function(serverConfig) {

fetchUserProfiles(serverConfig.USER_PROFILES, username,

function(profiles) {
currentProfile = profiles.currentProfile;

});

});

Kup książkę

Poleć książkę

background image

108 _

Rozdziaĥ 4. Analiza aplikacji AngularJS

Z powyĔszym podejĈciem zwiñzanych jest kilka problemów.

1.

Kod wynikowy bödzie koszmarnie powcinany, zwäaszcza jeĈli zajdzie

koniecznoĈè poäñczenia kilku wywoäaþ.

2.

Bäödy zgäaszane miödzy wywoäaniami zwrotnymi i funkcjami majñ

tendencjö do znikania, jeĔeli nie zostanñ röcznie obsäuĔone na kaĔdym

etapie.

3.

W wewnötrznym wywoäaniu zwrotnym konieczna jest hermetyza-

cja logiki zwiñzanej z dziaäaniami przeprowadzanymi za pomocñ

zmiennej currentProfile bezpoĈrednio lub za pomocñ oddzielnej

funkcji.

Obietnica rozwiñzuje wymienione problemy. Zanim siö przekonasz, w jaki

sposób, najpierw spójrz na ten sam kod, ale zaimplementowany z uĔyciem

obietnic:

var currentProfile = fetchServerConfig().then(function(serverConfig) {
return fetchUserProfiles(serverConfig.USER_PROFILES, username);

}).then(function(profiles) {

return profiles.currentProfile;

}, function(error) {

// Obsáuga báĊdów powstaáych w fetchServerConfig()

// lub w fetchUserProfiles().

});

Zwróè uwagö na zalety nowego rozwiñzania.

1.

Istnieje moĔliwoĈè äñczenia wywoäaþ funkcji i nie spowoduje to

koszmaru zwiñzanego ze stosowaniem wciöè w kodzie.

2.

Masz gwarancjö, Ĕe wywoäanie poprzedniej funkcji zostanie zakoþ-

czone, zanim nastñpi wywoäanie kolejnej funkcji w äaþcuchu.

3.

KaĔde wywoäanie then() pobiera dwa argumenty (oba to funkcje).

Pierwszy to funkcja wywoäywana w przypadku sukcesu operacji,

natomiast drugi to procedura obsäugi bäödów.

4.

W przypadku wystñpienia bäödów w äaþcuchu wspomniany bäñd bö-

dzie propagowany przez pozostaäe procedury obsäugi bäödów. Dla-

tego teĔ bäñd w dowolnym wywoäaniu zwrotnym moĔna obsäuĔyè

na koþcu.

MógäbyĈ zapytaè: co z wywoäaniami

resolve()

i

reject()

? Wywoäanie

deferred()

to we frameworku AngularJS sposób tworzenia obietnic. Z kolei

wywoäanie

resolve()

powoduje speänienie obietnicy (i wywoäanie pro-

cedury obsäugi w przypadku sukcesu operacji), podczas gdy wywoäanie

reject

powoduje wywoäanie procedury obsäugi bäödów w obietnicy.

Kup książkę

Poleć książkę

background image

Kontrolery, dyrektywy i usĥugi

_ 109

Do tego zagadnienia powrócimy jeszcze podczas konfiguracji tras.

Dyrektywy

Przechodzimy teraz do dwóch dyrektyw, które bödñ uĔywane w tworzo-

nej tutaj aplikacji.

butterbar

Ta dyrektywa bödzie pokazana lub ukryta w trakcie wczytywania in-
formacji przez stronö, a takĔe po zmianie trasy. Jest poäñczona z me-
chanizmem zmiany trasy i automatycznie zostaje ukryta lub umiesz-
czona w znaczniku na podstawie stanu strony.

focus

Ta dyrektywa jest uĔywana w celu zagwarantowania, Ĕe pewne pola
tekstowe (lub elementy) formularza sieciowego sñ aktywne.

Spójrz na przykäadowy fragment kodu:

// Plik: app/scripts/directives/directives.js.
var directives = angular.module('guthub.directives', []);

directives.directive('butterbar', ['$rootScope', function($rootScope) {
return {
link: function(scope, element, attrs) {
element.addClass('hide');

$rootScope.$on('$routeChangeStart', function() {
element.removeClass('hide');
});

$rootScope.$on('$routeChangeSuccess', function() {
element.addClass('hide');
});
}
};
}]);

directives.directive('focus', function() {
return {
link: function(scope, element, attrs) {
element[0].focus();
}
};
});

Przedstawiona dyrektywa zwraca obiekt wraz z pojedynczñ wäaĈciwoĈciñ

link

. Dokäadne omówienie tematu tworzenia wäasnych dyrektyw znajdziesz

w rozdziale 6., teraz musisz jedynie wiedzieè o dwóch rzeczach.

Kup książkę

Poleć książkę

background image

110 _

Rozdziaĥ 4. Analiza aplikacji AngularJS

1.

Dyrektywy przechodzñ przez proces skäadajñcy siö z dwóch etapów.

Na pierwszym etapie (faza kompilacji) nastöpuje wyszukanie wszystkich
dyrektyw doäñczonych do elementu drzewa DOM, a nastöpnie ich
przetworzenie. Wszelkie operacje na elementach drzewa DOM sñ

przeprowadzane na etapie kompilacji. Na koþcu fazy otrzymujesz funk-
cjö äñczñcñ.

2.

Na drugim etapie (faza äñczenia — tö fazö wczeĈniej wykorzystaliĈmy)

wygenerowany szablon elementów drzewa DOM jest doäñczany do za-

siögu (

scope

). Ponadto dodawane sñ wszelkie komponenty monitorujñce

lub nasäuchujñce, co oznacza powstanie funkcjonujñcego wiñzania miö-
dzy zasiögiem

scope

i elementem. Wszystko, co jest powiñzane z zasiögiem

scope

, zachodzi na etapie äñczenia.

Co siö dzieje w naszej dyrektywie? Zajrzyjmy do niej i przekonajmy siö.

Dyrektywa

butterbar

moĔe byè uĔywana w nastöpujñcy sposób:

<div butterbar>Komunikat informujÈcy o wczytywaniu...</div>

Dziaäanie dyrektywy polega na ukryciu elementu oraz dodaniu dwóch
komponentów monitorujñcych zasiög gäówny (

scope

). Za kaĔdym razem,

gdy rozpoczyna siö zmiana trasy, nastöpuje pokazanie elementu (przez
zmianö jego klasy), a po zakoþczonej powodzeniem zmianie trasy mamy
ponowne ukrycie dyrektywy

butterbar

.

Interesujñcñ cechñ, na którñ warto tutaj zwróciè uwagö, jest sposób wstrzyk-
niöcia

$rootScope

do dyrektywy. Wszystkie dyrektywy majñ bezpoĈrednie

powiñzanie z systemem wstrzykiwania zaleĔnoĈci w AngularJS, co pozwala
na wstrzykiwanie do nich usäug oraz innych niezbödnych komponentów.

Ostatnia kwestia warta uwagi to API przeznaczone do pracy z elementem.
ProgramiĈci przyzwyczajeni do biblioteki jQuery bödñ szczöĈliwi, wiedzñc,
Ĕe zastosowanie ma doskonale znana im skäadnia (

addClass

,

removeClass

).

Framework AngularJS implementuje pewien podzbiór wywoäaþ jQuery,
a wiöc biblioteka jQuery stanowi opcjonalnñ zaleĔnoĈè dla kaĔdego projektu
AngularJS. JeĔeli w projekcie chcesz wykorzystaè peäniö moĔliwoĈci ofe-
rowanych przez jQuery, wtedy powinieneĈ wiedzieè, Ĕe AngularJS uĔywa

jej zamiast wbudowanej implementacji.

Druga dyrektywa (

focus

) jest znacznie prostsza. Jej dziaäanie polega na wywo-

äaniu metody

focus()

dla bieĔñcego elementu. MoĔna jñ wywoäaè przez doda-

nie atrybutu

focus

do dowolnego elementu danych wejĈciowych, na przykäad:

<input type="text" focus></input>

Podczas wczytywania strony element automatycznie jest aktywny.

Kup książkę

Poleć książkę

background image

Kontrolery, dyrektywy i usĥugi

_

111

Kontrolery

Po zaprezentowaniu dyrektyw i usäug moĔesz wreszcie przejĈè do kon-
trolerów, których w naszej aplikacji mamy piöè. Wszystkie zostaäy zdefi-
niowane w pojedynczym pliku (app/scripts/controllers/controllers.js), ale omó-
wimy je tutaj pojedynczo. Przechodzimy wiöc do pierwszego kontrolera

(

ListCtrl

), odpowiedzialnego za wyĈwietlenie listy wszystkich przepisów

kulinarnych przechowywanych w systemie.

app.controller('ListCtrl', ['$scope', 'recipes', function($scope, recipes) {
$scope.recipes = recipes;
}]);

Zwróè uwagö na jednñ bardzo waĔnñ kwestiö w przypadku omawianego
kontrolera: w konstruktorze nie zawiera on Ĕadnego kodu dotyczñcego
nawiñzania poäñczenia z serwerem i pobrania przepisów kulinarnych.
Zamiast tego kod zajmuje siö obsäugñ wczeĈniej pobranych przepisów. Byè

moĔe zastanawiasz siö, jak to zostaäo zrobione. CóĔ, dokäadnñ odpowiedĒ
poznasz w sekcji poĈwiöconej routingowi, ale juĔ teraz moĔemy powie-
dzieè, Ĕe wiñĔe siö to z usäugñ

MultiRecipeLoader

. Po prostu o tym pamiötaj.

Po zapoznaniu siö z kontrolerem

ListCtrl

zobaczysz, Ĕe pozostaäe sñ caä-

kiem podobne do omówionego. Mimo wszystko zaprezentujemy je po
kolei, wskazujñc przy tym interesujñce aspekty:

app.controller('ViewCtrl', ['$scope', '$location', 'recipe',
function($scope, $location, recipe) {
$scope.recipe = recipe;

$scope.edit = function() {
$location.path('/edit/' + recipe.id);
};
}]);

Interesujñcym aspektem kontrolera

ViewCtrl

jest funkcja edycji udostöp-

niana obiektowi

scope

. Zamiast pokazywaè i ukrywaè pola lub stosowaè

podobne rozwiñzanie, kontroler wykorzystuje framework AngularJS i zleca
mu wykonanie najtrudniejszych zadaþ (powinieneĈ stosowaè takie samo
podejĈcie!). Funkcja

edit()

po prostu zmienia adres URL na odpowiednik

przepisu kulinarnego, a AngularJS zajmuje siö resztñ. Ponadto framework
wykrywa zmianö adresu URL i wczytuje odpowiedni widok (w trybie
edycji bödzie to po prostu dany przepis kulinarny). Wspaniale!

Przechodzimy teraz do kontrolera

EditCtrl

:

app.controller('EditCtrl', ['$scope', '$location', 'recipe',
function($scope, $location, recipe) {
$scope.recipe = recipe;

Kup książkę

Poleć książkę

background image

112

_

Rozdziaĥ 4. Analiza aplikacji AngularJS

$scope.save = function() {
$scope.recipe.$save(function(recipe) {
$location.path('/view/' + recipe.id);
});
};

$scope.remove = function() {
delete $scope.recipe;
$location.path('/');
};
}]);

W tym kontrolerze nowoĈciñ sñ metody

save()

i

remove()

, które

EditCtrl

udostöpnia obiektowi

scope

.

Metoda

save()

obiektu

scope

dziaäa zgodnie z oczekiwaniami. Zapisuje bie-

Ĕñcy przepis kulinarny, a po zakoþczeniu operacji zapisu przekierowuje
uĔytkownika do widoku wyĈwietlajñcego ten sam przepis. Funkcja wywoäa-

nia zwrotnego jest uĔyteczna, poniewaĔ pozwala na przeprowadzenie pew-
nych operacji po zapisie.

Istniejñ dwa sposoby zapisania przepisu. Jeden z nich zostaä przedstawio-
ny w kodzie i polega na wywoäaniu funkcji

$scope.recipe.$save()

. Takie

rozwiñzanie jest moĔliwe tylko dlatego, Ĕe

recipe

jest obiektem zasobu zwró-

conego przez

RecipeLoader

.

Natomiast drugi sposób zapisu to wywoäanie:

Recipe.save(recipe);

Metoda

remove()

równieĔ naleĔy do prostych, a jej dziaäanie polega na

usuniöciu przepisu z obiektu

scope

oraz przekierowaniu uĔytkownika na

stronö gäównñ. Zwróè uwagö, Ĕe nie powoduje to rzeczywistego usuniöcia
przepisu kulinarnego z serwera. Wykonanie dodatkowego wywoäania nie
powinno byè zbyt trudne.

Kolejny kontroler nosi nazwö

NewCtrl

:

app.controller('NewCtrl', ['$scope', '$location', 'Recipe',
function($scope, $location, Recipe) {
$scope.recipe = new Recipe({
ingredients: [ {} ]
});

$scope.save = function() {
$scope.recipe.$save(function(recipe) {
$location.path('/view/' + recipe.id);
});
};
}]);

Kup książkę

Poleć książkę

background image

Kontrolery, dyrektywy i usĥugi

_

113

Ten kontroler jest niemal dokäadnie taki sam jak

EditCtrl

(jako èwiczenie

mógäbyĈ oba wymienione kontrolery poäñczyè w jeden). Jedyna róĔnica

polega na tym, Ĕe pierwszym krokiem w dziaäaniu kontrolera

NewCtrl

jest

utworzenie nowego przepisu kulinarnego (wspomniany przepis to zasób,

a wiöc kontroler ma funkcjö

save()

). Caäa pozostaäa funkcjonalnoĈè nie

ulega zmianie.
Ostatni kontroler to

IngredientsCtrl

. Jest to kontroler specjalny, ale zanim

przejdziemy do jego omówienia, spójrz na tworzñcy go kod:

app.controller('IngredientsCtrl', ['$scope', function($scope) {
$scope.addIngredient = function() {

var ingredients = $scope.recipe.ingredients;

ingredients[ingredients.length] = {};

};

$scope.removeIngredient = function(index) {
$scope.recipe.ingredients.splice(index, 1);

};

}]);

Wszystkie przedstawione dotñd kontrolery sñ poäñczone z okreĈlonymi wi-

dokami w interfejsie uĔytkownika. Pod tym wzglödem kontroler

Ingredient-

sCtrl

dziaäa nieco inaczej. To po prostu kontroler potomny uĔywany do

edycji stron i hermetyzacji pewnych funkcji niepotrzebnych na ogólnym

poziomie. Warto w tym miejscu wspomnieè o pewnej interesujñcej kwestii.

Skoro to kontroler potomny, dziedziczy obiekt

scope

po kontrolerze nad-

rzödnym (w omawianym przykäadzie jest to kontroler

EditCtrl

lub

NewCtrl

).

Dlatego teĔ uzyskanie dostöpu do obiektu

$scope.recipe

odbywa siö z po-

ziomu kontrolera nadrzödnego.
Sam kod kontrolera nie zawiera nic szczególnie interesujñcego lub unikalnego.

Dodaje kilka nowych skäadników do tablicy skäadników przepisu kulinarnego

lub teĔ usuwa okreĈlony skäadnik z listy.
W ten sposób omówiliĈmy wszystkie kontrolery. Jedyny fragment kodu

JavaScript, jaki pozostaä do przeanalizowania, dotyczy konfiguracji routingu:

// Plik: app/scripts/controllers/controllers.js.
var app = angular.module('guthub',

['guthub.directives', 'guthub.services']);

app.config(['$routeProvider', function($routeProvider) {
$routeProvider.

when('/', {

controller: 'ListCtrl',

resolve: {
recipes: function(MultiRecipeLoader) {

return MultiRecipeLoader();
}
},

Kup książkę

Poleć książkę

background image

114 _

Rozdziaĥ 4. Analiza aplikacji AngularJS

templateUrl:'/views/list.html'
}).when('/edit/:recipeId', {
controller: 'EditCtrl',
resolve: {
recipe: function(RecipeLoader) {
return RecipeLoader();
}
},
templateUrl:'/views/recipeForm.html'
}).when('/view/:recipeId', {
controller: 'ViewCtrl',
resolve: {
recipe: function(RecipeLoader) {
return RecipeLoader();
}
},
templateUrl:'/views/viewRecipe.html'
}).when('/new', {
controller: 'NewCtrl',
templateUrl:'/views/recipeForm.html'
}).otherwise({redirectTo:'/'});
}]);

Zgodnie z wczeĈniejszñ obietnicñ docieramy do miejsca, w którym uĔy-

wana jest funkcja

resolve()

. W poprzednim fragmencie kodu skonfigu-

rowano moduä

guthub

AngularJS, a takĔe trasy i szablony wykorzystywane

w aplikacji.
Kod äñczy dyrektywy z utworzonymi przez nas usäugami, a nastöpnie

wskazuje róĔne trasy, które bödñ stosowane w aplikacji.
Dla kaĔdej trasy definiowany jest adres URL, kontroler odpowiedzialny za ob-

säugö danego adresu, wczytywany szablon, a takĔe (wreszcie) obiekt

resolve

.

Obiekt

resolve

nakazuje frameworkowi AngularJS speänienie wymagaþ

kaĔdego klucza, zanim trasa bödzie mogäa zostaè uĔyta do wyĈwietlenia
odpowiedniego widoku uĔytkownikowi. Zadanie aplikacji polega na wczy-
taniu wszystkich przepisów kulinarnych (lub tylko wskazanego), a serwer
ma udzieliè odpowiedzi przed wyĈwietleniem strony uĔytkownikowi. Do-
stawcö tras informujemy wiöc o posiadaniu przepisów kulinarnych (lub
przepisu), a nastöpnie podajemy mu sposób, w jaki majñ byè pobrane dane.
W trakcie wykonywania operacji pobierania danych wykorzystywane sñ

dwie usäugi (

MultiRecipeLoader

i

RecipeLoader

) zdefiniowane na poczñtku

tworzenia aplikacji. Framework AngularJS zostaä doĈè sprytnie zaprojek-

towany — jeĔeli wartoĈciñ zwrotnñ funkcji

resolve()

bödzie obietnica An-

gularJS, wtedy framework poczeka na speänienie wspomnianej obietnicy
przed przejĈciem dalej. Oznacza to koniecznoĈè zaczekania, aĔ serwer udzieli
odpowiedzi.

Kup książkę

Poleć książkę

background image

Kontrolery, dyrektywy i usĥugi

_

115

Wynik jest w postaci argumentów (o nazwach parametrów bödñcych po-
lami obiektu) przekazywany konstruktorowi.

Na koþcu funkcja

otherwise()

wskazuje domyĈlny adres URL dla przekie-

rowania, jeĈli nie nastñpi dopasowanie Ĕadnej trasy.

Byè moĔe zauwaĔyäeĈ, Ĕe kontrolery EditCtrl i NewCtrl korzy-
stajñ z tego samego szablonu, czyli views/recipeForm.html. Co siö tutaj
dzieje? Po prostu ponownie wykorzystaliĈmy szablon przezna-

czony do edycji przepisu kulinarnego. Szablon wyĈwietla róĔne

elementy w zaleĔnoĈci od wywoäanego kontrolera.

Po zakoþczeniu omawiania kontrolerów moĔemy przejĈè do szablonów.
Zobaczysz, w jaki sposób wymienione kontrolery zostaäy powiñzane z sza-
blonami, a takĔe dowiesz siö, jak zarzñdzaè danymi, które sñ wyĈwietlane

uĔytkownikowi.

Szablony

Rozpoczynamy od zapoznania siö z najbardziej zewnötrznym, gäównym
szablonem zdefiniowanym w pliku index.html. Stanowi on podstawö dla
naszej aplikacji skäadajñcej siö z pojedynczej strony, a wszystkie pozostaäe
widoki sñ wczytywane w kontekĈcie omawianego tutaj szablonu:

<!DOCTYPE html>
<html lang="pl" ng-app="guthub">
<head>
<title>GutHub - tworzenie przepisów kulinarnych i dzielenie siÚ nimi</title>
<script src="scripts/vendor/angular.min.js"></script>
<script src="scripts/vendor/angular-resource.min.js"></script>
<script src="scripts/directives/directives.js"></script>
<script src="scripts/services/services.js"></script>
<script src="scripts/controllers/controllers.js"></script>
<link href="styles/bootstrap.css" rel="stylesheet">
<link href="styles/guthub.css" rel="stylesheet">
</head>
<body>
<header>
<h1>GutHub</h1>
</header>

<div butterbar>Wczytywanie...</div>

<div class="container-fluid">
<div class="row-fluid">
<div class="span2">
<!-- Pasek boczny. -->

<div id="focus"><a href="#/new">Nowy przepis</a></div>

Kup książkę

Poleć książkę

background image

116 _

Rozdziaĥ 4. Analiza aplikacji AngularJS

<div><a href="#/">Lista przepisów</a></div>
</div>
<div class="span10">
<div ng-view></div>
</div>
</div>
</div>
</body>
</html>

W przedstawionym szablonie istnieje piöè elementów, na które warto zwró-
ciè uwagö. WiökszoĈè z nich miaäeĈ okazjö poznaè w rozdziale 2. Wspo-
mniane elementy omówimy po kolei.

ng-app

Ustawienie moduäu dla aplikacji GutHub. Jest to dokäadnie ten sam
moduä, który wykorzystaliĈmy we funkcji

angular.module()

. W ten sposób

framework AngularJS wie, jak wszystko ma zostaè ze sobñ poäñczone.

script znacznik

W tym miejscu nastöpuje wczytanie AngularJS w aplikacji. Framework
trzeba wczytaè przed wszystkimi plikami JavaScript, które go uĔywa-

jñ. W idealnej sytuacji znaczniki odpowiedzialne za wczytywanie
skryptów JavaScript powinny znajdowaè siö na koþcu pliku szablonu.

butterbar

Aha! To pierwsze uĔycie naszej wäasnej dyrektywy. Ta dyrektywa zo-
staäa zdefiniowana wczeĈniej i chcemy jñ wykorzystaè wraz z elemen-
tem wyĈwietlanym podczas zmiany trasy. Po zakoþczeniu powodze-
niem operacji zmiany trasy element powiñzany z dyrektywñ

butterbar

powinien zostaè ukryty. Dyrektywa powoduje wyĈwietlenie tekstu
(w omawianym przypadku jest to nudny komunikat

Wczytywanie...

), gdy

zachodzi potrzeba.

’Ècza href wartoĂci

To äñcza

href

do róĔnych stron naszej aplikacji skäadajñcej siö z poje-

dynczej strony. Zwróè uwagö na uĔycie znaku

#

gwarantujñcego, Ĕe

strona nie zostanie ponownie wczytana. Adresy sñ podawane wzglö-
dem strony bieĔñcej. Framework AngularJS monitoruje wspomniane
adresy URL (dopóki strona nie zostanie ponownie wczytana) i wykonuje
caäñ pracö zwiñzanñ z ich obsäugñ (w rzeczywistoĈci jest to bardzo

nudne zarzñdzanie trasami zdefiniowane przez nas wczeĈniej wraz
z trasami), gdy zachodzi potrzeba.

Kup książkę

Poleć książkę

background image

Kontrolery, dyrektywy i usĥugi

_

117

ng-view

W tym miejscu wykonywana jest pozostaäa czöĈè pracy. WczeĈniej we
fragmencie rozdziaäu poĈwiöconym kontrolerom zdefiniowaliĈmy trasy.
CzöĈciñ definicji jest adres URL trasy, powiñzany z niñ kontroler i sza-
blon. Kiedy framework AngularJS wykryje zmianö trasy, wtedy na-
stöpuje wczytanie szablonu, doäñczenie do niego kontrolera oraz za-

stñpienie elementu

ng-view

zawartoĈciñ szablonu.

Jedynñ rzeczñ rzucajñcñ siö w oczy jest brak znacznika

ng-controller

. Wiök-

szoĈè aplikacji zawiera pewnego rodzaju kontroler

MainController

powiñzany

z szablonem gäównym. Najczöstszym miejscem jego podania jest znacznik

<body>

. W omawianej aplikacji nie uĔywamy wspomnianego znacznika,

poniewaĔ caäy szablon gäówny nie zawiera treĈci AngularJS wymagajñcej

odwoäania do obiektu

scope

.

Spójrzmy teraz na szablony powiñzane z poszczególnymi kontrolerami. Na

poczñtek przyglñdamy siö szablonowi wyĈwietlajñcemu listö przepisów

kulinarnych:

<!-- Plik: chapter4/guthub/app/views/list.html. -->
<h3>Lista przepisów</h3>

<ul class="recipes">
<li ng-repeat="recipe in recipes">

<div><a ng-href="#/view/{{recipe.id}}">{{recipe.title}}</a></div>

</li>

</ul>

To naprawdö bardzo nudny szablon. Znajdujñ siö tutaj jedynie dwa intere-

sujñce punkty. Pierwszy to standardowy sposób uĔycia znacznika

ng-repeat

.

Zadanie wymienionego znacznika polega na pobraniu wszystkich przepisów

z obiektu

scope

, a nastöpnie ich wyĈwietleniu.

Drugi interesujñcy punkt to uĔycie znacznika

ng-href

zamiast

href

. Ma to

na celu unikniöcie wygenerowania nieprawidäowego äñcza podczas wczyty-

wania frameworka AngularJS. Znacznik

ng-href

gwarantuje, Ĕe w Ĕadnej

chwili uĔytkownikowi nie zostanie wyĈwietlony nieprawidäowy znacznik.

Wymienionego znacznika powinieneĈ uĔywaè zawsze, gdy adresy URL sñ

dynamiczne, a nie statyczne.
Byè moĔe zadajesz sobie pytanie: gdzie podziaä siö kontroler? Nie mamy

zdefiniowanego znacznika

ng-controller

i tak naprawdö nie ma zdefinio-

wanego kontrolera gäównego. W tym miejscu do gry wchodzi mapowanie

tras. MoĔe pamiötasz (mówiliĈmy o tym kilka stron wczeĈniej), Ĕe trasa /

powoduje przekierowanie do wyĈwietlajñcego listö przepisów kulinarnych

szablonu, któremu przypisano kontroler

ListCtrl

. Dlatego teĔ wszelkie od-

niesienia do zmiennych pozostajñ w zasiögu wymienionego kontrolera.

Kup książkę

Poleć książkę

background image

118 _

Rozdziaĥ 4. Analiza aplikacji AngularJS

Teraz przechodzimy do znacznie ciekawszego szablonu, czyli odpowiedzial-
nego za wyĈwietlenie przepisu.

<!-- Plik: chapter4/guthub/app/views/viewRecipe.html. -->
<h2>{{recipe.title}}</h2>

<div>{{recipe.description}}</div>

<h3>Skïadniki</h3>

<span ng-show="recipe.ingredients.length == 0">Brak skïadników</span>
<ul class="unstyled" ng-hide="recipe.ingredients.length == 0">
<li ng-repeat="ingredient in recipe.ingredients">
<span>{{ingredient.amount}}</span>
<span>{{ingredient.amountUnits}}</span>
<span>{{ingredient.ingredientName}}</span>
</li>
</ul>

<h3>Sposób przygotowania</h3>
<div>{{recipe.instructions}}</div>

<form ng-submit="edit()" class="form-horizontal">
<div class="form-actions">
<button class="btn btn-primary">Edycja</button>
</div>
</form>

To kolejny maäy, przydatny szablon. Warto zwróciè uwagö na dwa punkty
powyĔszego szablonu, choè niekoniecznie w kolejnoĈci ich wymienienia.

Pierwszy to caäkiem standardowy sposób uĔycia dyrektywy

ng-repeat

.

Przepisy kulinarne znajdujñ siö w zasiögu kontrolera

ViewCtrl

wczytanego

przez funkcjö

resolve()

przed wyĈwietleniem strony uĔytkownikowi. Dziöki

temu gwarantujemy prawidäowe dziaäanie strony, gdy zostaje wyĈwietlona.

Drugi punkt to uĔycie dyrektywy

ng-submit

w formularzu. Wymieniona

dyrektywa oznacza, Ĕe wysäanie formularza spowoduje wywoäanie funkcji

edit()

obiektu

scope

. Wysäanie formularza nastöpuje, gdy klikniöty bödzie

przycisk niepowiñzany z Ĕadnñ funkcjñ (w omawianym przypadku to
przycisk Edycja). I znów dziaäanie frameworka AngularJS zostaäo zaprojek-
towane bardzo sprytnie — potrafi on prawidäowo ustaliè zasiög, do którego
ma siö odwoäywaè (na przykäad: moduäu, trasy lub kontrolera), i wywoäaè
odpowiedniñ metodö we wäaĈciwym czasie.

Teraz moĔemy przejĈè do ostatniego (i prawdopodobnie najbardziej skom-
plikowanego) szablonu, czyli formularza pozwalajñcego na dodanie lub edy-

cjö przepisu kulinarnego.

Kup książkę

Poleć książkę

background image

Kontrolery, dyrektywy i usĥugi

_

119

<!-- Plik: chapter4/guthub/app/views/recipeForm.html. -->
<h2>Edycja przepisu</h2>
<form name="recipeForm" ng-submit="save()" class="form-horizontal">
<div class="control-group">
<label class="control-label" for="title">Nazwa:</label>
<div class="controls">
<input ng-model="recipe.title" class="input-xlarge" id="title" focus required>
</div>
</div>

<div class="control-group">
<label class="control-label" for="description">Opis:</label>
<div class="controls">
<textarea ng-model="recipe.description" class="input-xlarge"
id="description"></textarea>
</div>
</div>

<div class="control-group">
<label class="control-label" for="ingredients">Skïadniki:</label>
<div class="controls">
<ul id="ingredients" class="unstyled" ng-controller="IngredientsCtrl">
<li ng-repeat="ingredient in recipe.ingredients">
<input ng-model="ingredient.amount" class="input-mini">
<input ng-model="ingredient.amountUnits" class="input-small">
<input ng-model="ingredient.ingredientName">
<button type="button" class="btn btn-mini"
ng-click="removeIngredient($index)"><i class="icon-minus-sign"></i>
Usuñ</button>
</li>
<button type="button" class="btn btn-mini" ng-click="addIngredient()">
<i class="icon-plus-sign"></i>Dodaj</button>
</ul>
</div>
</div>

<div class="control-group">
<label class="control-label" for="instructions">Sposób
przygotowania:</label>
<div class="controls">
<textarea ng-model="recipe.instructions" class="input-xxlarge"
id="instructions"></textarea>
</div>
</div>

<div class="form-actions">
<button class="btn btn-primary" ng-disabled="recipeForm.$invalid">Zapisz
</button>
<button type="button" ng-click="remove()" ng-show="!recipe.id" class="btn">
Usuñ</button>
</div>
</form>

Kup książkę

Poleć książkę

background image

120 _

Rozdziaĥ 4. Analiza aplikacji AngularJS

Nie panikuj! Wyglñda na to, Ĕe szablon zawiera caäkiem sporñ iloĈè kodu,
i faktycznie tak jest. Jednak po rzeczywistym zagäöbieniu siö weþ moĔna
siö przekonaè, Ĕe kod nie jest skomplikowany. Tak naprawdö to prosta,
powtarzajñca siö struktura, pokazujñca, jak edytowalne pola tekstowe zo-

staäy zastosowane w formularzu przeznaczonym do edycji przepisów ku-
linarnych.

x

W pierwszym polu tekstowym (

title

) zostaäa umieszczona dyrektywa

focus

. Dziöki temu po przejĈciu na tö stronö wskazane pole zostanie

wybrane, a uĔytkownik bödzie mógä natychmiast rozpoczñè wprowa-

dzanie danych wejĈciowych.

x

Dyrektywa

ng-submit

jest uĔyta w bardzo podobny sposób jak w po-

przednim przykäadzie, a wiöc nie bödziemy jej tutaj dokäadnie oma-
wiaè. Warto wiedzieè, Ĕe powoduje zapisanie stanu przepisu kulinarne-
go i wskazuje koniec procesu edycji. Ponadto jest powiñzana z funkcjñ

save()

zdefiniowanñ w kontrolerze

EditCtrl

.

x

Dyrektywa

ng-model

säuĔy do poäñczenia róĔnych pól tekstowych for-

mularza sieciowego z polami modelu.

x

Jednym z najbardziej interesujñcych aspektów omawianej strony jest
umieszczona w czöĈci poĈwiöconej liĈcie skäadników dyrektywa

ng-

controller

, której naprawdö warto poĈwiöciè nieco uwagi i spróbowaè

w peäni zrozumieè sposób jej dziaäania. Zobaczmy wiöc, co siö tutaj
dzieje.
Lista skäadników jest wyĈwietlana, a zawierajñcy jñ znacznik jest po-
wiñzany z dyrektywñ

ng-controller

. Oznacza to, Ĕe caäy znacznik

<ul>

znajduje siö w zasiögu kontrolera

IngredientsCtrl

. MógäbyĈ w tym

miejscu zapytaè: co z rzeczywistym kontrolerem

EditCtrl

powiñzanym

z szablonem? Jak siö okazuje,

IngredientsCtrl

jest tworzony jako kon-

troler potomny

EditCtrl

i tym samym dziedziczy po nim. Dlatego teĔ

dostöp do obiektu

recipe

nastöpuje z poziomu kontrolera

EditCtrl

.

Ponadto kontroler

IngredientsCtrl

dodaje metodö

addIngredient()

uĔy-

wanñ przez dyrektywö

ng-click

i dostöpnñ jedynie w zasiögu znacz-

nika

<ul>

. Dlaczego zdecydowaliĈmy siö na takie rozwiñzanie? To naj-

lepszy sposób na rozdzielenie obowiñzków. Po co umieszczaè metodö

addIngredient()

w kontrolerze

EditCtrl

, skoro 99% szablonu jej nie po-

trzebuje? Kontrolery potomne i zagnieĔdĔone doskonale sprawdzajñ siö
w tego rodzaju sytuacjach i pozwalajñ na oddzielenie logiki biznesowej
przez umieszczenie jej w äatwiejszych do zarzñdzania elementach.

Kup książkę

Poleć książkę

background image

Kontrolery, dyrektywy i usĥugi

_

121

x

Pozostaäe dyrektywy, które chcemy tutaj omówiè, sñ kontrolkami prze-
znaczonymi do weryfikacji formularza sieciowego. We frameworku
AngularJS moĔna bardzo äatwo okreĈliè, Ĕe dane pole formularza jest
wymagane. W tym celu wystarczy dodaè do tego pola dyrektywö

required

(jak to zrobiono w omawianym fragmencie kodu). Rodzi siö jednak
pytanie: co dalej?
Przechodzimy do przycisku Zapisz. Zwróè uwagö na uĔycie dyrekty-
wy

ng-disabled

, która ma wartoĈè

recipeForm.$invalid

. Czäon pierwszy

(

recipeForm

) to nazwa formularza zawierajñcego deklaracjö dyrektywy.

Framework AngularJS dodaje do niego pewne zmienne specjalne (za-
liczamy do nich

$valid

i

$invalid

) pozwalajñce na kontrolowanie ele-

mentów formularza sieciowego. AngularJS wyszukuje wszystkie wy-
magane elementy, a nastöpnie odpowiednio uaktualnia wspomniane
zmienne specjalne. JeĔeli pole säuĔñce do podania nazwy przepisu kuli-
narnego pozostanie niewypeänione, wartoĈciñ

recipeForm.$invalid

bödzie

true

(a wartoĈciñ

$valid

bödzie

false

) i przycisk Zapisz zostanie zablo-

kowany.

Istnieje równieĔ moĔliwoĈè okreĈlenia minimalnej i maksymalnej däugoĈci
pola tekstowego, a takĔe wzorzec wyraĔenia regularnego przeznaczonego
do przeprowadzenia weryfikacji danego pola. Co wiöcej, pewne funkcje
zaawansowane moĔna wykorzystaè do wyĈwietlania komunikatów bäödów
po wystñpieniu pewnych okreĈlonych warunków. Spójrzmy na prosty
przykäad:

<form name="myForm">
Nazwa uĝytkownika:<input type="text"
name="userName"
ng-model="user.name"
ng-minlength="3">
<span class="error"
ng-show="myForm.userName.$error.minlength">Zbyt krótka!</span>
</form>

Za pomocñ uĔycia dyrektywy

ng-minlength

w powyĔszym fragmencie ko-

du zdefiniowano, Ĕe nazwa uĔytkownika musi skäadaè siö z przynajmniej
trzech znaków. Teraz formularz zostaje wypeäniony danymi pochodzñcymi
z obiektu

scope

— w omawianym przykäadzie to jedynie

userName

. Wszystkie

pola tekstowe majñ obiekt

$error

(zawiera informacje o rodzaju ewentual-

nego bäödu:

required

,

minlength

,

maxlength

lub

pattern

) oraz wäaĈciwoĈè

$valid

wskazujñcñ poprawnoĈè bñdĒ teĔ niepoprawnoĈè danych wejĈciowych.

Kup książkę

Poleć książkę

background image

122 _

Rozdziaĥ 4. Analiza aplikacji AngularJS

Takie rozwiñzanie pozwala na selektywne wyĈwietlanie uĔytkownikowi

komunikatu bäödu w zaleĔnoĈci od jego rodzaju, jak to pokazano w powyĔ-

szym fragmencie kodu.
Do drugiego przycisku doäñczona jest dyrektywa

ng-click

uĔywana pod-

czas usuwania przepisu kulinarnego. Zwróè uwagö, Ĕe przycisk jest wy-

Ĉwietlany tylko wtedy, gdy przepis nie zostaä jeszcze zapisany. Wprawdzie

znacznie sensowniejsze wydaje siö uĔycie

ng-hide="recipe.id"

, ale czasami

bardziej semantyczne rozwiñzanie to

ng-show="!recipe.id"

. Oznacza to wy-

Ĉwietlenie przycisku, gdy przepis kulinarny nie zawiera identyfikatora,

zamiast ukrywania przycisku, jeĈli przepis ma zdefiniowany identyfikator.

Testy

WstrzymywaliĈmy siö z przedstawieniem testów wraz z kontrolerami, ale

musiaäeĈ siö spodziewaè, Ĕe kiedyĈ wreszcie do nich przejdziemy. W tym

podrozdziale zaprezentowane zostanñ testy, które naleĔy utworzyè dla

przygotowanego dotñd fragmentu kodu. Dowiesz siö równieĔ, jak tworzy

siö takie testy.

Testy jednostkowe

NajwaĔniejszy rodzaj testów to testy jednostkowe. Pozwalajñ one na spraw-

dzenie, czy opracowane kontrolery (dyrektywy i usäugi) majñ prawidäowñ

strukturö i konstrukcjö oraz czy dziaäajñ zgodnie z oczekiwaniami.

Zanim przejdziemy do poszczególnych testów jednostkowych, warto spoj-

rzeè na szkielet przeznaczony dla wszystkich testów jednostkowych doty-

czñcych kontrolera:

describe('Kontrolery', function() {
var $scope, ctrl;
// W teĞcie naleĪy wskazaü moduá.

beforeEach(module('guthub'));
beforeEach(function() {
this.addMatchers({
toEqualData: function(expected) {
return angular.equals(this.actual, expected);
}
});
});

describe('ListCtrl', function() {....});

// Miejsce na opisanie pozostaáych kontrolerów.
});

Kup książkę

Poleć książkę

background image

Testy

_ 123

Przygotowany szkielet (tutaj nadal wykorzystujemy styl Jasmine do tworze-
nia testów) wykonuje kilka zadaþ.

1.

Tworzy globalnie (przynajmniej dla testu) dostöpny obiekt

scope

i kon-

troler, a wiöc nie trzeba siö przejmowaè tworzeniem nowej zmiennej
dla kaĔdego kontrolera.

2.

Inicjalizuje moduä uĔywany przez aplikacjö (w omawianym przykäadzie

jest to GutHub).

3.

Dodaje specjalne dopasowanie nazywane

equalData

. Pozwala ono na prze-

prowadzanie asercji na obiektach Ēródäa (na przykäad przepisach kuli-
narnych) zwracanych przez usäugö

$resource

lub na wywoäanie RESTful.

Pamiötaj o koniecznoĈci dodania specjalnego dopasowania na-

zywanego equalData za kaĔdym razem, gdy zachodzi potrzeba

stosowania asercji na zwróconych obiektach ngResource. WiñĔe

siö to z faktem, Ĕe zwrócone obiekty ngResource majñ metody do-
datkowe, których zwykäe wykonanie zakoþczy siö niepowodze-

niem, poniewaĔ oczekiwane sñ wywoäania equalData.

Majñc przygotowany szkielet, spójrzmy na gotowy test jednostkowy prze-
znaczony dla kontrolera

ListCtrl

:

describe('ListCtrl', function() {
var mockBackend, recipe;
// _$httpBackend_ to nazwa taka sama jak $httpBackend. Zastosowany zapis sáuĪy do odróĪnienia

// zmiennych wstrzykniĊtych od zmiennych lokalnych.

beforeEach(inject(function($rootScope, $controller, _$httpBackend_, Recipe) {
recipe = Recipe;
mockBackend = _$httpBackend_;
$scope = $rootScope.$new();
ctrl = $controller('ListCtrl', {
$scope: $scope,
recipes: [1, 2, 3]
});
}));

it('Wynikiem powinna byÊ lista przepisów kulinarnych', function() {
expect($scope.recipes).toEqual([1, 2, 3]);
});
});

Jak zapewne pamiötasz, kontroler

ListCtrl

naleĔy do najprostszych w apli-

kacji. Konstruktor kontrolera pobiera po prostu listö przepisów, a nastöp-
nie zapisuje je w obiekcie. Wprawdzie moĔna do tego utworzyè test, ale

wydaje siö to zbödne. W omawianym przykäadzie mimo wszystko utwo-
rzyliĈmy test, poniewaĔ testy jednostkowe sñ wspaniaäe!

Kup książkę

Poleć książkę

background image

124 _

Rozdziaĥ 4. Analiza aplikacji AngularJS

Znacznie ciekawiej robi siö w przypadku usäugi

MultiRecipeLoader

. Wy-

mieniona usäuga jest odpowiedzialna za pobranie listy przepisów kulinar-
nych z serwera i przekazanie ich jako argumentu (kiedy zastosowana jest
prawidäowa konfiguracja za pomocñ usäugi

$route

):

describe('MultiRecipeLoader', function() {
var mockBackend, recipe, loader;
// _$httpBackend_ to nazwa taka sama jak $httpBackend. Zastosowany zapis sáuĪy do odróĪnienia

// zmiennych wstrzykniĊtych od zmiennych lokalnych.

beforeEach(inject(function(_$httpBackend_, Recipe, MultiRecipeLoader) {
recipe = Recipe;
mockBackend = _$httpBackend_;
loader = MultiRecipeLoader;
}));

it('Wynikiem powinno byÊ wczytanie listy przepisów kulinarnych', function() {
mockBackend.expectGET('/recipes').respond([{id: 1}, {id: 2}]);

var recipes;

var promise = loader();
promise.then(function(rec) {
recipes = rec;
});

expect(recipes).toBeUndefined();
mockBackend.flush();
expect(recipes).toEqualData([{id: 1}, {id: 2}]);
});
});
// Miejsce na opisanie pozostaáych kontrolerów.

Test usäugi

MultiRecipeLoader

odbywa siö przez przygotowanie usäugi

Http

´

Backend

w naszym teĈcie. Obiekt pochodzi z pliku angular-mocks.js i jest

doäñczany w trakcie przeprowadzania testów. Po prostu wstrzykniöcie go
do metody

beforeEach()

jest wystarczajñce, aby moĔna byäo konfigurowaè

oczekiwania. W drugim, znacznie ciekawszym teĈcie oczekiwanie zostaäo
zdefiniowane jako wywoäanie

server GET

do recipes, a wynikiem powinna

byè tablica obiektów. Nastöpnie uĔywamy dopasowania w celu spraw-
dzenia, czy uzyskany wynik jest dokäadnie zgodny z oczekiwaniami. Zwróè
uwagö na wywoäanie

flush()

w obiekcie makiety, przekazujñce odpowiedĒ

pochodzñcñ z serwera. Tego rodzaju mechanizm moĔna wykorzystaè do
przetestowania przepäywu kontroli i sprawdzenia, jak aplikacja dziaäa przed

otrzymaniem odpowiedzi z serwera i po jej otrzymaniu.

Pomijamy kontroler

ViewCtrl

, poniewaĔ jest niemal identyczny z

ListCtrl

,

poza dodatkiem w postaci metody

edit()

. Wymieniona metoda jest bardzo

äatwa do przetestowania: wystarczy wstrzyknñè usäugö

$location

do testu

i sprawdziè jej wartoĈè.

Kup książkę

Poleć książkę

background image

Testy

_ 125

Przechodzimy teraz do kontrolera

EditCtrl

, który z perspektywy testów

jednostkowych ma dwa interesujñce punkty. Funkcja

resolve()

jest podobna

do uĔywanej juĔ poprzednio i moĔe byè przetestowana w dokäadnie ten
sam sposób jak wczeĈniej w rozdziale. Zamiast tego zobaczysz teraz, jak

moĔna przetestowaè metody

save()

i

remove()

. Spójrzmy wiöc na wymienione

testy (przyjöto zaäoĔenie o uĔyciu szkieletu przedstawionego w poprzednim
przykäadzie):

describe('EditCtrl', function() {
var mockBackend, location;
beforeEach(inject(function($rootScope,
$controller,
_$httpBackend_,
$location,
Recipe) {
mockBackend = _$httpBackend_;
location = $location;
$scope = $rootScope.$new();

ctrl = $controller('EditCtrl', {
$scope: $scope,
$location: $location,
recipe: new Recipe({id: 1, title: 'Przepis'})
});
}));

it('Wynikiem powinien byÊ zapisany przepis kulinarny', function() {
mockBackend.expectPOST('/recipes/1',
{id: 1, title: 'Przepis'}).respond({id: 2});

// Ustawienie innej wartoĞci, aby mieü gwarancjĊ jej zmiany podczas testu.

location.path('test');

$scope.save();
expect(location.path()).toEqual('/test');

mockBackend.flush();

expect(location.path()).toEqual('/view/2');
});

it('Wynikiem powinno byÊ usuniÚcie przepisu kulinarnego', function() {
expect($scope.recipe).toBeTruthy();
location.path('test');

$scope.remove();

expect($scope.recipe).toBeUndefined();
expect(location.path()).toEqual('/');
});
});

Kup książkę

Poleć książkę

background image

126 _

Rozdziaĥ 4. Analiza aplikacji AngularJS

W pierwszym teĈcie sprawdzane jest dziaäanie funkcji

save()

. W szczegól-

noĈci upewniamy siö, Ĕe operacja zapisu powoduje wykonanie do serwera
Ĕñdania

POST

wraz z obiektem. Nastöpnie, po udzieleniu odpowiedzi przez

serwer, przechodzimy na stronö zawierajñcñ nowo zapisany przepis kulinarny.

Drugi test jest jeszcze prostszy. Po prostu sprawdzamy, czy wywoäanie
funkcji

remove()

powoduje usuniöcie wskazanego przepisu kulinarnego,

a nastöpnie przekierowujemy uĔytkownika na stronö docelowñ. Jest to äatwe
do wykonania dziöki wstrzykniöciu usäugi

$location

do testu i jej uĔyciu.

Pozostaäa czöĈè testów jednostkowych dla kontrolerów wykorzystuje te same
wzorce, a wiöc moĔna je tutaj pominñè. Ogólnie rzecz ujmujñc, testy jed-
nostkowe opierajñ siö na kilku aspektach:

x

zagwarantowanie, Ĕe kontroler (lub bardziej prawdopodobnie obiekt

scope

) osiñgnie prawidäowy stan na koþcu procesu inicjalizacji;

x

potwierdzenie wykonania prawidäowych wywoäaþ serwera i osiñgniöcie

wäaĈciwego stanu przez obiekt

scope

w trakcie wspomnianych wywo-

äaþ serwera oraz po ich zakoþczeniu (do tego celu w testach jednost-
kowych uĔywany jest obiekt makiety);

x

wykorzystanie funkcji wstrzykiwania zaleĔnoĈci we frameworku An-

gularJS, aby uzyskaè uchwyt do elementów i obiektów uĔywanych przez
kontroler. Pozwala to upewniè siö, Ĕe kontroler ustawia prawidäowy stan.

Testy scenariuszy

Gdy testy jednostkowe zakoþczñ siö powodzeniem, moĔe pojawiè siö po-
kusa zakoþczenia pracy. Jednak praca programisty AngularJS nie koþczy
siö, zanim nie bödñ przeprowadzone testy scenariuszy. Wprawdzie testy

jednostkowe dajñ gwarancjö, Ĕe kaĔdy najmniejszy fragment kodu Java-
Script dziaäa zgodnie z oczekiwaniami, ale jednoczeĈnie warto siö upewniè
o wczytaniu szablonów, prawidäowym powiñzaniu kontrolerów i poprawnej
reakcji na klikniöcia elementów szablonu.

Dokäadnie do tego celu säuĔñ testy scenariuszy we frameworku AngularJS.
Pozwalajñ one na:

x

wczytanie aplikacji;

x

przejĈcie na konkretnñ stronö;

x

klikniöcie i wprowadzenie tekstu;

x

upewnienie siö o prawidäowej reakcji aplikacji.

Kup książkę

Poleć książkę

background image

Testy

_ 127

Na jakiej zasadzie dziaäa test scenariusza dla strony wyĈwietlajñcej listö
przepisów kulinarnych? Przede wszystkim przed rozpoczöciem rzeczywi-
stego testu trzeba poczyniè pewne przygotowania.

Aby ten test scenariusza dziaäaä, konieczne jest przygotowanie serwera

WWW, który bödzie miaä moĔliwoĈè akceptacji Ĕñdaþ wykonywanych
przez aplikacjö GutHub, a takĔe pobierania listy przepisów kulinarnych
z testowanej aplikacji oraz ich przechowywania. MoĔesz zmodyfikowaè kod
i wykorzystaè zapisywanñ w pamiöci listö przepisów — wymaga to usu-
niöcia

$resource

dla przepisu i zmiany usäugi na obiekt zawierajñcy dane

w formacie JSON. Ewentualnie moĔna ponownie wykorzystaè i zmodyfiko-
waè serwer WWW przedstawiony w poprzednim rozdziale bñdĒ teĔ uĔyè

narzödzia Yeoman!

Po przygotowaniu i uruchomieniu serwera WWW obsäugujñcego aplikacjö
wystarczy utworzyè i wykonaè przedstawiony poniĔej test:

describe('GutHub App', function() {
it('Wynikiem powinna byÊ lista przepisów kulinarnych', function() {
browser().navigateTo('/index.html');
// DomyĞlna lista przepisów kulinarnych w aplikacji GutHub skáada siĊ jedynie z dwóch pozycji.

expect(repeater('.recipes li').count()).toEqual(2);
});
});

Kup książkę

Poleć książkę

background image

128 _

Rozdziaĥ 4. Analiza aplikacji AngularJS

Kup książkę

Poleć książkę

background image

217

Skorowidz

A

analiza aplikacji, 101
anatomia aplikacji, 23
API, 150
API HTML5, 174
API jQuery, 165
aplikacje

AJAX, 57
mobilne, 61
sieciowe, 11

architektura MVC, 14, 24
arkusze stylów CSS, 39
asynchroniczne wywoäania metod, 130
atak typu XSRF, 147
atrybut

href, 42
multiple, 203
ng-app, 19
ng-change, 30
ng-controller, 44
ng-model, 20, 45, 193
ng-repeat, 19, 37

required, 66
src, 42

B

bezpieczeþstwo, 146
biblioteka

jQuery, 110
NodeJS, 76
RequireJS, 92
Socket.IO, 76, 129, 204

blok

Config, 179
Run, 179

bäödy, 173
buforowanie odpowiedzi, 134

C

ciasteczka, 184

D

dane wejĈciowe, 65
debugowanie, 85
definiowanie kontrolerów, 111
deklaracja

dyrektywy, 201
kontrolera, 194
zasobu, 140

dodawanie trasy, 90
doäñczanie danych, 14, 20, 27
DOM, Document Object Model, 14, 63, 164
dostöp do

konsoli, 87
zasiögu, 160

dwukropek, 140
dyrektywa, 17, 149

butterbar, 109, 116, 211
errorMessage, 212
expander, 167
focus, 65, 95, 109

ng-app, 24
ng-bind, 29
ng-bind-html, 189
ng-bind-html-unsafe, 189
ngbkFocus, 65
ng-class, 40
ng-click, 65, 122
ng-controller, 120
ng-disabled, 67
ng-hide, 38
ng-minlength, 121
ng-model, 120
ngPluralize, 186
ng-repeat, 37, 41, 118, 196, 200

Kup książkę

Poleć książkę

background image

218 _ Skorowidz

dyrektywa

ng-style., 40
ng-submit, 32, 118, 120
ng-view, 58

dyrektywy

dostöp do zasiögu, 160
funkcja compile(), 157
funkcja link(), 157
nazwa, 152
obsäuga zdarzeþ, 32

opcja priority, 153
opcja templates, 154
opcja transclude, 157
wäaĈciwoĈè restrict, 152

dyskretny kod JavaScript, 33
dziaäanie

dyrektywy, 110
filtru, 57
funkcji save(), 126
opcji dyrektywy, 164
testu, 99
usäugi $location, 174

E

edycja przepisu, 118

element

<input>, 66
ng-app, 116
ng-href, 117
ng-repeat, 117
ng-show, 38
ng-view, 117

elementy

drzewa DOM, 36, 164
powtarzalne, 36
szablonu, 116
tablicy, 42

F

faza

kompilacji, 158

äñczenia, 158

filtr, 55

filterService, 200
linky, 189, 190

filtrowanie, 196

daty i godziny, 188
listy, 80

formatowanie danych, 55
formularz, 29
formularz rejestracyjny, 65
framework

BDD, 79
Express, 75

funkcja

$http.get(), 130
$resource, 140
$scope. safeApply(), 173
$watch(), 30, 45–50
addExpander(), 168
callback, 208
callMe(), 50
compile(), 158
computeNeeded(), 31
controller(), 165
directive(), 63
done, 203
edit(), 118
equals(), 143

factory(), 53, 181
focus(), 64, 110
inheritedData(), 165
injector(), 165
link(), 64, 158
otherwise(), 58, 115
provider(), 53, 181
remove(), 21, 112
resolve(), 114, 118, 125
run(), 156
save(), 112
scope(), 165
select(), 194
selectRow(), 41
service(), 53, 181

StartUpController(), 31
stun(), 39
then(), 107, 143
totalCart(), 47

funkcje

jQuery, 165
typu getter, 175
typu setter, 175
usäugi $location, 174

Kup książkę

Poleć książkę

background image

Skorowidz

_ 219

G

granice aplikacji, 24

grupowanie zaleĔnoĈci, 51

H

harmonijka, 168

hermetyzacja, 142

I

IDE, 73

identyfikator lokalizacji, 186

informacje o lokalizacji, 173

instalacja

Karma, 96

Yeoman, 89

integracja z IDE, 79

interceptor, 212

interfejs

document.cookie, 184

uĔytkownika, 19

internacjonalizacja aplikacji, 185, 188

K

karta

kredytowa, 139

Model, 86

Performance, 86

katalog

app, 93

config, 93

test, 93

klasa HelloController, 13

kod

lokalizacji, 186

serwera, 75

usäugi, 105

kompilacja, 82

kompilator Closure Compiler, 83

komponent nasäuchujñcy, 183

komunikacja

miödzy kontrolerami, 196

miödzy zasiögami, 182

z serwerami, 61, 129

z usäugami, 211

konfiguracja

moduäu, 180

routingu, 113

Ĉrodowiska programistycznego, 92

testów jednostkowych, 96

zasiögu, 161

Ĕñdania, 131

konstruktor kontrolera, 167

kontroler, 14, 25, 43, 103, 166

CartController, 21, 47

EditCtrl, 111, 120, 125

FilterCtrl, 196

HelloController, 13

IngredientsCtrl, 113

ListCtrl, 111, 117, 123, 196

NamesListCtrl, 136

NewCtrl, 112

RootController, 212

SearchController, 185

ViewCtrl, 111

kontrolka datepicker, 191, 194

koszyk na zakupy, 18, 48

L

lista, 36

logika

aplikacji, 14, 65

biznesowa, 142

lokalizacja, 185, 186

luka w zabezpieczeniach, 146

Ĥ

äñcza

bezwzglödne, 177

href, 116

wzglödne, 177

M

menedĔer NPM, 77

metoda, Patrz funkcja

metody

konfiguracji moduäu, 180

moduäu AngularJS, 178

obiektu Recipe, 106

obiektu zdarzenia, 184

Kup książkę

Poleć książkę

background image

220 _ Skorowidz

model, 14, 25, 102
moduä

gäówny, 179
guthub, 114
ngResource, 138
ngSanitize, 189

Sanitize, 188

modyfikacja

ciasteczka, 148

Ĕñdania, 132

monitorowanie

elementów, 50

zmian, 45

MVC, 14, 24

N

nagäówek

Authorization, 213

DO NOT TRACK, 133

nagäówki

HTTP, 133

uwierzytelnienia, 211

narzödzia, 73, 84

narzödzie

Ant, 92

Batarang, 85

karta Model, 86

karta Performance, 86

wäaĈciwoĈci elementów, 87

zaleĔnoĈci usäugi, 87

Karma, 76–78, 96

RequireJS, 92

Scenario Runner, 80, 82

WebStorm, 73

Yeoman, 70, 75

dodawanie tras, 90

funkcje, 88

instalacja, 89

testy, 91

tworzenie projektu, 90

nasäuchiwanie zdarzeþ, 183

nawias klamrowy, 28

nazwa dyrektywy, 152

ngResource, 142

notacja

{{ }}, 20

interpolacji, 39

NPM, Node Package Manager, 77

O

obiekt

$scope, 44
config, 131, 135
Recipe, 106
resolve, 114
scope, 136
zdarzenia, 184

obiektowy model dokumentu, 14

obiekty wstrzymane, 107
obietnica, 107, 143
obsäuga

bäödów, 145, 210
HTML5, 63
kodów stanu, 212
liczby mnogiej, 186
lokalizacji, 187
äñczy, 176
przekierowaþ, 211
RequireJS, 96
zdarzeþ, 32, 33

ochrona przed lukñ, 147
oczyszczanie kodu HTML, 188
opakowanie kontrolki jQuery, 191

opcje

dyrektywy, 151
wäaĈciwoĈci require, 167

operacje

bitowe, 42
logiczne, 42
matematyczne, 42
po stronie serwera, 142

optymalizacja, 83

Simple, 83
zaawansowana, 83

organizacja projektu, 70, 92

P

pasek

nawigacyjny, 35

tytuäu, 162

plik

angular.js, 187
app.js, 94
controller.js, 60
controllers.js, 64, 95

Kup książkę

Poleć książkę

background image

Skorowidz

_ 221

detail.html, 59
index.html, 58, 64, 95
karma.config.js, 78
list.html, 59
main.js, 95, 98

pliki

aplikacji, 70
JavaScript, 70
konfiguracyjne, 72, 78
szablonów HTML, 71

pokazywanie elementów, 38
pole

combo, 200
tekstowe, 29, 120
wyboru, 200
wyszukiwania, 199

porównania, 42
prawo Demeter, 17
produkty, 55
programowanie, 69
projekt jQuery-File-Upload, 201
prototypowe dziedziczenie, 26
przechwycenie odpowiedzi, 145
przedstawianie danych, 14

przekazywanie plików, 201
przenoszenie treĈci, 157
przepisy kulinarne, 102
przepisywanie äñczy, 177
przycisk zerowania, 32
publikacja danych modelu, 44

S

Scenario Runner, 80, 82
schematy weryfikacji HTML, 150
serwer

Karma, 78
RESTful, 106
Socket.IO, 206
WWW, 75, 90

serwis GitHub, 62

strategie wiñzania, 161
strefy czasowe, 188
stronicowanie, 207
styl Jasmine, 80, 123
style CSS, 39
szablon, 15, 17, 27, 54, 103
szablon po stronie klienta, 12

Ļ

ĈcieĔki app/img, 71
Ĉrodowisko IDE, 73, 79

T

tabela, 36
tablica currentPageItems, 209
TDD, Test-driven development, 76
technika TDD, 76, 80
test, 99

ACID, 35
integracji, 72, 80
jednostkowy, 72, 79, 122, 135, 142
kontrolera, 136
metody, 125
scenariusza, 126, 127
typu E2E, 72, 80, 99
usäugi, 124, 208

testowanie, 76
token, 148
transformacje

odpowiedzi, 134
Ĕñdania, 134

trasa, 44, 57, 114
tryb

hashbang, 175
HTML5, 175

tworzenie

aplikacji sieciowych, 11
dyrektyw, 109, 150
filtrów, 56
funkcji dyrektywy, 63
interfejsu uĔytkownika, 14
obiektu wstrzymanego, 107
obietnic, 108
paska, 162
projektu, 90, 91
szablonu, 12, 115
trasy, 57
usäug, 53

zasiögu, 160

typ zasiögu, 161

Kup książkę

Poleć książkę

background image

222 _ Skorowidz

U

uaktualnianie listy, 196
ukrywanie

bäödów, 212
elementów, 38

uruchamianie

aplikacji, 28, 75
serwera, 90
testów, 91

röczne, 81
zautomatyzowane, 81

usäuga, 53, 105

$cookies, 185
$cookieStore, 185
$http, 61, 129, 137, 142
$httpProvider, 135
$location, 17, 57, 124, 171

funkcje, 174
integracja AngularJS, 173
integracja HTML5, 174
tryb hashbang, 175
tryb HTML5, 175

$q, 143
$route, 57, 124

$routeProvider, 57
Authentication, 213, 214
Error, 211
errorService, 211
filterService, 196
MultiRecipeLoader, 124
Pagination, 210
Paginator, 208
stronicowania, 207

uwierzytelnienie Ĕñdania, 213
uĔycie

atrybutu ng-model, 45
biblioteki Socket.IO, 204
dyrektywy, 153
dyrektywy focus, 65

filtrów, 196
funkcji $watch(), 45, 48
kontrolerów, 43, 166
Pythona, 76
Scenario Runner, 82
serwera WWW, 75, 81
transformacji, 135
usäugi $location, 174

WebStorm, 74
wyraĔenia, 45
Yeoman, 75
zasobów AngularJS, 138

W

wczytywanie

moduäu, 179
skryptu, 23

weryfikacja

danych wejĈciowych, 65
kodu HTML, 149
pól formularza, 66

wiñzanie select, 193
widok, 14, 25, 44
wielokrotne

uĔycie kodu, 170
uĔycie komponentów, 170

wäaĈciwoĈci

AngularJS, 89
elementów, 87
obiektu, 42
obiektu zdarzenia, 184

wäaĈciwoĈè

$scope.isDisabled, 40

$valid, 66
innerHtml, 15
require, 167
window.location, 171, 173

wskazanie

atrybutu select, 195
lokalizacji, 57

wstrzykiwanie

usäugi, 96
zaleĔnoĈci, 16, 126

wtyczka

Batarang, 85
FileUpload, 203

wydajnoĈè aplikacji, 83
wykonywanie testów, 98

wyraĔenia, 42
wyĈwietlanie

listy, 196
tekstu, 28, 118

wywoäania

API, 180
zwrotne, 141

Kup książkę

Poleć książkę

background image

Skorowidz

_ 223

wywoäanie

$apply, 172
AngularJS, 23
factory(), 180
provider(), 181
scope.$apply, 172
select(), 194
service(), 181

wyzerowanie wartoĈci pola tekstowego, 32
wzorzec Singleton, 183

X

XHR, 130
XSRF, 147

Z

zabezpieczenia JSON, 146
zagnieĔdĔenie zasiögów, 86
zaleĔnoĈci, 51, 71, 179

RequireJS, 94
usäugi, 87

zarzñdzanie

danymi, 14
moduäami, 179
zaleĔnoĈciami, 92

zasada minimalnej wiedzy, 17

zasiög, 44, 86, 160, 182

globalny, 26
gäówny $rootScope, 182
nadrzödny, 161, 183
odizolowany, 160
potomny, 161, 183

zasoby

AngularJS, 138
RESTful, 106, 137
statyczne, 71

zasób karty kredytowej, 139
zdarzenia zasiögu, 183
zdarzenie

click, 166
loginRequired, 211
on-select, 194
select, 195

zintegrowane Ĉrodowisko

programistyczne, IDE, 73

zlokalizowany zestaw reguä, 187
zmiana

elementów drzewa DOM, 63
widoków, 57

znacznik, Patrz element
znacznik semantyczny, 34

znak

dolara, 53
dwukropka, 140

ś

Ĕñdanie, 131

CreditCard, 139
DELETE, 138
GET, 138
POST, 107, 138
XHR, 130

Ĕywe szablony, 74

Kup książkę

Poleć książkę

background image

O autorach

Brad Green

pracowaä nad projektem AngularJS jako menedĔer inĔynierów w Google,

gdzie jest odpowiedzialny równieĔ za kwestie zwiñzane z uäatwieniami dostöpu i pomoc
technicznñ. Przed podjöciem pracy w Google zajmowaä siö tworzeniem witryn interne-
towych dla urzñdzeþ przenoĈnych w AvantGo, zakäadaä i sprzedawaä start-upy, a kilka
lat spödziä na mozolnej pracy osoby organizujñcej przyjöcia i bankiety. Wkrótce po
ukoþczeniu szkoäy podjñä swñ pierwszñ pracö w zaäoĔonej przez Steve’a Jobsa firmie
NeXT Computer, w której odpowiadaä za przygotowywanie wersji demo oprogramowa-

nia i slajdów do prezentacji Jobsa. Brad wraz z Ĕonñ i dwójkñ dzieci mieszka w Mountain
View w stanie Kalifornia.

Shyam Seshadri

jest wäaĈcicielem i szefem Fundoo Solutions (http://www. befundoo.com/),

gdzie czas dzieli miödzy pracö nad innowacyjnymi i ekscytujñcymi nowymi produktami
na rynek indyjski a Ĉwiadczeniem usäug konsultingowych i prowadzeniem warsztatów
dotyczñcych AngularJS. Przed utworzeniem Fundoo Solutions zdobyä tytuä magistra na
prestiĔowej indyjskiej uczelni Indian School of Business w Hajdarabadzie. Po ukoþcze-
niu szkoäy pracowaä dla Google, gdzie zajmowaä siö róĔnorodnymi projektami, miödzy
innymi Google Feedback (pierwsza aplikacja oparta na frameworku AngularJS!), oraz
innymi narzödziami i projektami wewnötrznymi. Obecnie pracuje w swoim biurze w Nawi
Mumbaj w Indiach.

Kolofon

Zwierzö widniejñce na okäadce ksiñĔki AngularJS to Lactoria fornasini — morska ryba roz-

dymkoksztaätna naleĔñca do rodziny kosterowatych (Ostraciidae) i rodzaju Lactoria. ēyje na
skalistych rafach lub piaszczystym dnie, schowana i zaplñtana pomiödzy gñbkami oraz
wodorostami. Wystöpuje w zachodniej czöĈci oceanów Spokojnego i Indyjskiego. ēywi
siö gäównie robakami i innymi bezkrögowcami.

Lactoria

osiñga 15 centymetrów däugoĈci i od 3 do 50 centymetrów szerokoĈci. Osobniki za-

liczane do rodziny kosterowatych wyróĔniajñ siö szeĈciokñtnym wzorem päytek kost-
nych tworzñcych pancerz na ich skórze. Z ciaäa, przypominajñcego trójkñtne pudeäko,
wystajñ päetwy i ogon umoĔliwiajñce im poruszanie siö. Wraz z wiekiem ksztaät ciaäa koste-
rowatych zmienia siö od nieco zaokrñglonego do kwadratowego, a kolor skóry staje siö
bardziej jaskrawy.

Lactoria fornasini

chroni siö przed niebezpieczeþstwem, wydzielajñc przez skórö substan-

cje powierzchniowo czynne uruchamiane pod wpäywem stresu. Toksyny, zwykle wydalane
w postaci Ĉluzu, przenikajñ do Ĉrodowiska, draĔniñc inne ryby i organizmy znajdujñce siö
w niedalekim sñsiedztwie.

Rysunek na okäadce pochodzi ze zbiorów Johnson’s Natural History. Czcionka na okäadce

to Adobe ITC Garamond. Czcionka tekstu to Adobe Minion Pro, czcionka w nagäów-
kach — Adobe Myriad Condensed, kody zostaäy napisane czcionkñ Dalton Maag’s
Ubuntu Mono.

Kup książkę

Poleć książkę

background image
background image

Wyszukiwarka

Podobne podstrony:
DIGITAL OUTPUT ANGULAR ACCELEROMETER 8556
Angular?arings
DIGITAL OUTPUT ANGULAR ACCELEROMETER 8556
Nowoczesne aplikacje internetowe MongoDB Express AngularJS Node js noapin
Nowoczesne aplikacje internetowe MongoDB Express AngularJS Node js
AngularJS Pierwsze kroki 2
Projektowanie nowoczesnych aplikacji sieciowych z uzyciem AngularJS i Bootstrapa pnasab
AngularJS Szybkie wprowadzenie angusw
AngularJS angula 2
Nowoczesne aplikacje internetowe MongoDB Express AngularJS Node js 2
What you need to know about Angular 2
Nowoczesne aplikacje internetowe MongoDB Express AngularJS Node js noapin
AngularJS Pierwsze kroki angupk
AngularJS Pierwsze kroki

więcej podobnych podstron