Tutorial AngularJS: tworzymy pierwszą aplikację
Zaczynamy budowę naszej aplikacji w AngularJS zupełnie od zera. Na początek więc stwórzmy prostą stronę HTML, do której później dołączymy biblioteki AngularJS. Otwórz więc swój ulubiony edytor tekstowy i wpisz następujący kod, a następnie zapisz jako plik HTML:
<!DOCTYPE html>
<head>
<meta charset=”UTF-8”>
<title>Kurs AngularJS</title>
</head>
<body>
</body>
</html>
Jako, że mamy już pusty dokument HTML, który stanowi bazę dla naszej aplikacji, czas podłączyć pod niego framework AngularJS. Wchodzimy na stronę https://angularjs.org/ i klikamy DOWNLOAD. Kopiujemy link z okienka w polu CDN (https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js) i dołączamy go jako zewnętrzny skrypt do naszej strony w części<head></head>
.
<!DOCTYPE html>
<head>
<meta charset=”UTF-8”>
<title>Kurs AngularJS</title>
<script type=”text/javascript” src=”https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>
</head>
<body>
</body>
</html>
Okej, teraz możemy już zacząć używać AngularJS na naszej stronie. Najpierw musimy jednak wyraźnie zaznaczyć, w którym miejscu będziemy używać tego frameworka. Robimy to poprzez dodanie zbiorczego bloku div
i nadajemy mu atrybut ng-app
. Ten atrybut jest tzw. dyrektywą AngularJS. W dalszej części naszej aplikacji zobaczysz inne atrybuty zaczynające się od ng-, one wszystkie są dyrektywami, czyli niejako poleceniami AngularJS. Dyrektywa ng-app
mówi, że będziemy w tym miejscu korzystać z kodu AngularJS. Opcjonalnie możemy podać jej wartośc, która będzie nazwą aplikacji – jest to przydatne szczególnie w zaawansowanych projektach. Ja użyłem „PremierySeriali”. Od razu dodałem też klasę „container”, która przyda nam się później, gdy do naszej aplikacji podłączymy Bootstrapa.
<!DOCTYPE html>
<head>
<meta charset=”UTF-8”>
<title>Kurs AngularJS</title>
<script type=”text/javascript” src=” https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>
</head>
<body>
<div class="container" ng-app=’PremierySeriali’>
</div>
</body>
</html>
No dobra, mamy już stronę przygotowaną pod naszą aplikację „PremierySeriali”. Ale gdzie właściwie znajduje się ta aplikacja? No właśnie, musimy ją stworzyć! Otwieramy ulubiony edytor tekstowy i tworzymy nowy plik aplikacja.js
. W środku wpisujemy kod:
var apka = angular.module('PremierySeriali',[]);
I zapisujemy plik. Pamiętaj, aby plik aplikacja.js
zapisać w tym samym folderze, co plik html. Powyzszy kod tworzy moduł angular, który będzie zawierał naszą aplikację. Ma taki sam tytuł, jak użylismy w pliku html (PremierySeriali) i przypisuje go do nowej zmiennej apka. Moduły, jak pewnie się domyślasz, pozwalają dzielić naszą aplikację na części, a każda część zajmuje się np. inną funkcjonalnością. Do potrzeb tego tutoriala wystarczy nam jeden moduł.
Zanim przystąpimy do kolejnego kroku, warto nadmienić, ze AngularJS jest frameworkiem działajacym w oparciu o architekturę MVC, czyli Model – View – Controller. Czym jest każda z tych części? Najłatwiej myśleć o Modelu jako o zestawie danych – większość dynamicznych aplikacji webowych opiera się właśnie na danych. W AngularJS możemy oczywiście sami rozpisać nasze dane w pliku, ale najczęściej wykorzystuje się połączenia z istniejącymi bazami danych lub plikami JSON. Dane wyświetlamy użytkownikom za pomocą kolejnej części architektury MVC, mianowicie View. Można porównać View (widok) do szablonu dla wyświetlanych danych. W AngularJS tworzymy widoki informacji (Views) poprzez umieszczanie podwójnych nawiasów klamrowych {{}}
w kodzie HTML. Ostatnią częścią architektury są Kontrolery, które stanowią pomost między modelem a widokiem. Kontroler pozwala wzbogacić zestaw danych w modelu o jakieś funkcjonalności. Tworzymy więc kolejny plik, w którym umieścimy kontroler, którego będziemy używać do przeprowadzania operacji na danych:
apka.controller("MojController", function($scope,$http){
});
Nazwijmy ten plik kontroler.js
I również umieśćmy w folderze z naszą aplikacją. Powyższy plik przypisuje kontroler MojController do aplikacji „apka”. Zamiast tworzyć oddzielny plik .js
na kontroler, mogliśmy umieścić wszystko w jednym pliku, ale myślę, że powinniśmy pielęgnować troskę o czytelność kodu, bez względu czy to tutorial czy oficjalna aplikacja. Zatem połączmy dwa stworzone właśnie pliki, aplikacja.js
oraz kontroler.js
z plikiem html
, a utworzony kontroler dodajmy do naszego elementu div#container
za pomocą dyrektywyng-controller
:
<!DOCTYPE html>
<head>
<meta charset=”UTF-8”>
<title>Kurs AngularJS</title>
<script type=”text/javascript” src=” https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js”></script>
<script src="aplikacja.js" type="text/javascript"></script> <!-- aplikacja angularJS -->
<script src="kontroler.js" type="text/javascript"></script> <!-- glowny controller przypisany do aplikacji AngularJS -->
</head>
<body>
<div class="container" ng-app=’PremierySeriali’ ng-controller='MojController'>
</div>
</body>
</html>
Teraz możemy już korzystać z kontrolera w naszej aplikacji, a konkretnie w elemencie div #container
. Sprawdźmy, czy to działa. W pliku kontroler.js
, być może zauważyłeś, gdy tworzyliśmy kontroler, od razy stworzyliśmy funkcję $scope
. Utwórzmy przykładową zmienną w tej funkcji:
apka.controller("MojController", function($scope,$http){
$scope.mojtekst = "Witaj w mojej aplikacji AngularJS!";
});
i spróbujmy się do niej odwołać w naszym pliku html przy pomocy nawiasów klamrowych:
...
<div class="container" ng-app=’PremierySeriali’ ng-controller='MojController'>
{{mojtekst}}
</div>
...
Jeśli wszystko zrobiliśmy, jak trzeba, przeglądarka powinna wyrenderować tekst:
Wszystko gra, a więc możemy przystąpić do kolejnego kroku.
Zaciągamy dane do aplikacji
Okej, jak wspomniałem na wstępie, nasza aplikacja będzie wyświetlała nowości serialowe. Potrzebujemy więc danych o tych serialach. Skorzystamy z API serwisu www.themoviedb.org. Aby korzystać z API, potrzebny nam jest klucz. Aby otrzymać klucz API, należy założyć (darmowe) konto na stronie themoviedb.org i wejść do zakładki API.
Klucz jest nam potrzebny, aby nie tracić czasu na ręczne tworzenie bazy danych po stronie naszego serwera, a także aby bazować na rzetelnych informacjach z serwisu, który na co dzień zajmuje się kinematografią. W ten sposób możemy założyć, że nasza aplikacja po ukończeniu będzie rzeczywiście użyteczna.
Po zdobyciu klucza do API, dodajemy go do naszego kontrolera. Wchodzimy do pliku kontroler.js
i usuwamy poprzednią zadeklarowaną zmienną mojetekst
, na jej miejsce tworzymy nową, która przechowywać będzie nasz klucz API:
apka.controller("MojController", function($scope,$http){
$scope.kluczApi = "..."; // wstaw swój klucz api - np. d9eb45644e9.....
});
Lektura dokumentacji API serwisu themoviedb.org dostarcza nam informacji, jak stworzyć odwołanie, które prześle nam dane potrzebne do naszej aplikacji. Chodzi mianowicie o odwołanie ‘ first_air_date.gte‘, które pozwoli nam otrzymać seriale, które pierwszy raz pojawiły się w telewizji po wpisanej przez nas dacie. API oczekuje daty w formacie YYYY-MM-DD. Nasza aplikacja ma wyświetlać nowości, które pojawiły się w telewizji w tym miesiącu, musimy więc jeszcze określić, jaki dzisiaj jest miesiąc.
var dzisiaj = new Date();
var miesiac = dzisiaj.getFullYear() + “-“ + (“0” + (dzisiaj.getMonth() + 1)).slice(-2) + “-“ + (“0” + dzisiaj.getDate()).slice(-2);
W powyższym kodzie najpierw pobieramy dzisiejszą datę za pomocą JavaScriptowej funkcji ‘Date()‘, następnie wykorzystujemy ją w odpowiedni sposób w zmiennej ‘var miesiąc‘ aby uzyskać datę w wymaganym formacie.
Następnie wykorzystujemy tę zmienną do odwołania się do API za pomocą ‘$http.jsonp‘:
$http.jsonp("https://api.themoviedb.org/3/discover/tv?first_air_date.gte=" + miesiac + "&sort_by=popularity.desc&api_key=’+kluczApi+’&callback=JSON_CALLBACK").success(function(data) {
})
Ubieramy wszystko w funkcję ‘glowna‘ i w efekcie nasz plik ‘kontroler.js‘ powinien wyglądać tak:
apka.controller(„MojController”, function($scope,$http){
$scope.kluczApi = „...”; // wstaw swój klucz api - np. d9eb45644e9.....
$scope.glowna = function() {
var dzisiaj = new Date();
var miesiac = dzisiaj.getFullYear() + “-“ + (“0” + (dzisiaj.getMonth() + 1)).slice(-2) + “-“ + (“0” + dzisiaj.getDate()).slice(-2);
$http.jsonp("https://api.themoviedb.org/3/discover/tv?first_air_date.gte=" + miesiac + "&sort_by=popularity.desc&api_key=’+$scope.kluczApi+’&callback=JSON_CALLBACK").success(function(dane) {
}).error(function(error) {
alert(‘Houston, mamy problem z uzyskaniem danych.’);
});
};
});
Jak widzisz, wzbogaciłem adres odwołania do API o ciąg &sort_by=popularity.desc
. Dzięki temu lista seriali, którą otrzymamy będzie posortowana pod kątem popularności serialów. Na koniec ciągu dodajemy jeszcze zmienną &callback=JSON_CALLBACK
, aby upewnić się, że odpowiedź serwera będzie w formacie JSON.
Jeśli chcesz sprawdzić „na sucho” odwołanie do API, wstaw link prosto do przeglądarki, wpisując jakąś datę (na skrinie poniżej jest to 2014-09-01). Powinieneś otrzymać czystą odpowiedź w formacie JSON:
Na jej podstawie możemy stwierdzić, jakie dane o każdym serialu otrzymamy w ramach odpowiedzi z serwera: "id" "original_name" "first_air_date" "origin_country" "poster_path" "popularity" "name" "vote_average" "vote_count"
Dodałem jeszcze alert
na wypadek, gdyby nie udało się wykonać połączenia z API. Otrzymane z API dane musimy jeszcze gdzieś przechować. Zadeklarujmy tablicę w obrębie funkcji $scope:
$scope.wyniki = [];
Następnie wykorzystajmy tablicę do zgromadzenia danych z API:
$scope.wyniki = dane.results;
Po tych modyfikacjach plik kontroler.js
przedstawia się następująco:
apka.controller(„MojController”, function($scope,$http){
$scope.kluczApi = "..."; // wstaw swój klucz api - np. d9eb45644e9.....
$scope.wyniki = [];
$scope.glowna = function() {
var dzisiaj = new Date();
var miesiac = dzisiaj.getFullYear() + “-“ + (“0” + (dzisiaj.getMonth() + 1)).slice(-2) + “-“ + (“0” + dzisiaj.getDate()).slice(-2);
$http.jsonp("https://api.themoviedb.org/3/discover/tv?first_air_date.gte=" + miesiac + "&sort_by=popularity.desc&api_key=’+$scope.kluczApi+’&callback=JSON_CALLBACK").success(function(dane) {
$scope.wyniki = dane.results;
}).error(function(error) {
alert("Houston, mamy problem z uzyskaniem danych.");
});
};
});
Wyświetlamy pobrane dane
Czas wyświetlić informacje o serialach w naszej aplikacji. Wracamy do pliku html i dodajemy atrybut ng-init
z nazwą naszej głównej funkcji do div.container
. W ten sposób upewniamy się, że ta funkcja będzie wywołana jako pierwsza z naszej angularnej aplikacji po wyświetleniu strony. W elemenciediv.container’ powinieneś mieć odwołanie do naszej testowej zmiennej
{{mojtekst}}`. Usuń więc je.
<div class="container" ng-app='PremierySeriali' ng-controller='MojController' ng-init='glowna()'>
{{mojtekst}} <!--- <-kasujemy -->
</div>
Teraz bierzemy się za wyświetlenie danych na naszej stronie. Skorzystamy z dyrektywy ng-repeat
, która pozwoli nam dynamicznie wyświetlić zawartość danych w tablicy wyniki[]
jako np. listę. Gotowy kod wygląda tak:
<div class="container" ng-app='PremierySeriali' ng-controller='MojController' ng-init='glowna()' >
<div class="row">
<div class="col-md-2" ng-repeat='serial in wyniki'>
<h2>{{serial.original_name}}</h2>
</div>
</div>
</div>
Po uruchomieniu w przeglądarce, otrzymujemy listę serialowych premier miesiąca. W moim przypadku wygląda tak:
Zanim dodamy nowe funkcjonalności, ubierzmy naszą aplikację w estetyczne wdzianko. Najlepiej sprawdzi się Boostrap, popularny framework, umożliwiający szybkie tworzenie projektów stron, także responsywnych. Pobieramy Bootstrapa i dodajemy go do naszej strony, tworząc także prosty szablon za pomocą obecnych w Bootstrapie gotowych modułów. Nie będę się rozwodził nad nimi w szczegółach w tym tutorialu, wszak skupiamy się tu na AngularJS.
<!DOCTYPE html>
<head>
<meta charset="UTF-8">
<title>Kurs AngularJS</title>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/angularjs/1.2.26/angular.min.js"></script>
<script src="aplikacja.js" type="text/javascript"></script> <!-- aplikacja angularJS -->
<script src="kontroler.js" type="text/javascript"></script> <!-- glowny controller przypisany do aplikacji AngularJS -->
<link rel="stylesheet" type="text/css" href="css/bootstrap.min.css"><!-- bootstrap -->
<link rel="stylesheet" type="text/js" href="css/bootstrap.min.js"><!-- bootstrap -->
</head>
<body>
<div class="navbar navbar-inverse" role="navigation">
<div class="container">
<div class="navbar-header">
<a class="navbar-brand" href="#">Serialowe nowości</a>
</div>
</div>
</div>
<div class="container" ng-app='PremierySeriali' ng-controller='MojController' ng-init='glowna()' >
<div class="row">
<div class="col-md-2" ng-repeat='serial in wyniki'>
<img ng-show="serial.poster_path != null" src="https://image.tmdb.org/t/p/w185{{serial.poster_path}}" style="height:272px" />
<img ng-show="serial.poster_path == null" src="images/brak-postera.jpg" />
<h2>{{serial.original_name}}</h2>
</div>
</div>
</div>
</body>
</html>
Ponadto, posługując się zmienną serial.poster_path
możemy wyświetlić plakat do każdego serialu. Jeśli plakatu nie ma w otrzymanym z API zestawie danych, wyświetlamy informującą o tym grafikę. Odpowiada za to dyrektywa ng-show
, która sprawdza, czy serial.poster_path
istnieje, a następnie wyświetla stosowny <img>
. Drobnym kłopotem jest fakt, że plakaty niektórych seriali w bazie themoviedb.org mają większą wysokość od pozostałych, co czasem może powodować rozjeżdzanie się naszej aplikacji, która wyświetla seriale w formie siatki. Rozwiązaniem jest utrzymanie stałego rozmiaru plakatów za pomocą atrybutu style="height:272px
dla tagu img
.
Gotowa aplikacja powinna wyglądać mniej więcej w poniższy sposób. Wyświetlane są premierowe seriale w danym miesiącu, a zawartość zmienia się dynamicznie w zależności od tego, jaki aktualnie mamy miesiąc – bazując na danych z API serwisu themoviedb.org.
Jestem ciekaw, jak rozwiniesz swoją aplikację – samo API daje jeszcze sporo możliwości rozbudowy naszej angularnej apki o nowe funkcjonalności. Zachęcam do eksperymentowania – wszyscy wiemy, że to najlepszy sposób na naukę.
Dzień dobry;
Bardzo przystępny artykuł, sporo wyjaśniający. Będę wiernym czytelnikiem następnych.
Pozdrawiam
J.K.
dziękuję i również pozdrawiam.