WywołanieCzęść NR.3Witam w trzeciej części kursu o Angular 1.X. Poprzednim razem omówiliśmy kontrolery. Postanowiłem też dodać informacje o tym, do jakiej wersji ten kurs się odwołuje. Wersja Angular 2.0 jeszcze się nie pojawiła, ale twórcy tej wersji wywracają wszystko do góry nogami.

Przykładowo: nie będzie w niej kontrolerów.

Oficjalnie twórcy, mimo wszystko radzą używać obecnej wersji. Twórcy też wierzą, że 1.X. jest nadal dobra i nie ma potrzeby aktualizować jej do wersji 2.0, gdy będzie to możliwe. Taką informację otrzymałem od autora książki o Angular, na spotkaniu WODNUG.

Przejdźmy do naszego kursu.

Wiemy już czym są kontrolery i jakie funkcje spełniają. Przejdźmy do wywołań HTTP.

$http

Wewnątrz kontrolera zwykle nie wpisujemy danych na sztywno. Dane skądś pobieramy. W poprzednim wpisie dodałem informacje, wpisując je bezpośrednio do kontrolera. W prawdziwym życiu to tak nie działa.

Musimy pobrać dane od serwera. Serwer, przykładowo może wyciągnąć dane z serwera baz danych lub z plików XML.

Na poziomie JavaScript nas nie obchodzi, co serwer robi. Potrzebujemy po prostu danych. Musimy więc mieć możliwość, by dane z serwera przesłać do klienta JavaScript.

Pobieranie danych wykonuje się poprzez metody HTTP. Po stronie serwera istnieją adresy stron, których celem jest zwrócenie tych danych. Wywołujemy metodą HTTP na tej stronie i w nagrodę za to otrzymujemy dane w formacie JSON, co tak naprawdę później jest obiektem JavaScript.

W Angular ta technika określa się przez wyrażenie $http.

Szczegóły wywołań http są zaszyte wewnątrz Angular, więc nie musimy się tym przejmować.

Co więcej Angular posiada metody GET,POST,PUT,DELETE potrzebne do różnych wywołań HTTP.

Wywołanie GET do HTTP służy głównie do prostego odczytu danych. POST wysyła bardziej złożone dane i są one bardziej ukryte. PUT i DELETE mają określać akcję danego obiektu. Słowo PUT można z kojarzyć z umieszczeniem danych do serwera. Słowo DELETE z kasowaniem danych z serwera.

Jak to zrobić? Jak wywołać zapytanie HTTP w Angular.

var PersonController = function ($scope,$http) {
    $scope.name = "Cezary"
    $scope.surname = "Walenciuk"
}

Angular po prostu pyta wewnątrz danego kontrolera o dane. Podobnie jak wcześniej ze $scope mogę zapytać Angular o to, że będę potrzebował wywołania http. Wystarczy, że do parametrów funkcji reprezentujących nasz kontroler dodam zmienną $http.

Musi ona zaczyna się od znaku dolara i musi być napisana z małej litery, gdyż JavaScript jest wrażliwe na wielkość liter w zmiennych.

Gdy już mam obiekt $http. Mogę użyć następujących metod

  • $http.get
  • $http.post
  • $http.put
  • $http.delete.
var PersonController = function ($scope, $http) {
    var person = $http.get("/people/1473");
    $scope.name = person.name;
    $scope.surname = person.surname;
}

var SkillsController = function ($scope, $http) {


    var programing = $http.get("/programingSkils/2")

    var speaches = $http.get("/speachesSkills/4")

    $scope.programing = programing;
    $scope.speech = speaches;
}

Wyrażenie “$http.get” wyśle zapytanie HTTP na adres strony, w której obecnie się on znajduje plus “/people/1474”. Przykładowo:

http://cezarywalenciuk.pl/people/1473

Hipotetycznie pobrałby on z tego adresu obiekt reprezentujący daną osobę. 1473 reprezentuje identyfikator tejże osoby.

W drugim kontrolerze pobralibyśmy z odpowiednich adresów informację o umiejętności programowania o określonym numerze 2. Pobraliśmy również informację na temat umiejętności przemawiania.

Oba kontrolery używają jednak wywołania HTTP i Angulara w zły sposób.

Wyrażenie $http.get nie zwróci obiektu natychmiast. Wyrażenie to uruchomi tylko zapytanie do serwera.

Wywołanie HTTP jest asynchroniczne. Obiekt się pojawi, ale później. Musimy więc operować na obietnicach.

Wyrażenie $http.get zwróci tak naprawdę obiekt obietnicy.Obietnica polega na założeniu, że w przyszłości, w tym miejscu pojawią się nasze dane.

Użycie obietnic wygląda tak.

var PersonController = function ($scope, $http) {

    var promise = $http.get("/persons/1473");

    promise.then(function (response) {
        $scope.name = response.data.name;
        $scope.surname = response.data.surname;
    });
}

var SkillsController = function ($scope, $http) {

    var promisePro = $http.get("/programingSkils/2")
    var promiseSpeach = $http.get("/speachesSkills/4")

    promisePro.then(function (response) {
        $scope.programing = response.data;
    });

    promiseSpeach.then(function (response) {
        $scope.speech = response.data;
    });
}

Na obiekcie obietnicy mogę przypisać swoją funkcję do właściwości “then”, która się wykona, gdy zapytanie się skończy.

Mogę też skrócić całe to wyrażenie używając łańcucha wywołań

var PersonController = function ($scope, $http) {

    $http.get("/persons/1473").
        then(function (response) {
        $scope.name = response.data.name;
        $scope.surname = response.data.surname;
    });
}

Przejdźmy do przykładu z prawdziwego życia. Nie możemy przecież działać na hipotetycznym serwerze i hipotetycznych stronach, gdzie można wywołać zapytania HTTP.

GitHub API

Na tej stronie posiadam kurs ASP.NET WEB API. Przerabiając go powinieneś być w stanie napisać swoją własną usługę http, która będzie zwracać informację.

Jednak na tym kursie nie będę uczył, jak po stronie serwera taką usługę napisać. Być może nie masz nic wspólnego z platformą .NET. Może jesteś programistą Ruby on Rails i się tą platformą brzydzisz.

Do użycia Angulara jakieś API będzie nam potrzebne. Facebook, Twitter, LinkedIn wymaga podania hasła użytkownika przed jakimkolwiek użyciem.

Do takiej zabawy najlepiej użyć GitHub. Nie musimy przesyłać naszych danych do tego API. Użycie więc jest bardzo proste.

Ma ona także inne cechy, które sprawiają, że API znakomicie nadaje się do nauki. Jest ona dostępna dla klienta JavaScript wewnątrz przeglądarki oraz zwraca JSON, który jest łatwo konwertowany na obiekt JavaScript.

Mogę też wywołać tę usługę z poziomu przeglądarki. Moje konto GitHub jest bardzo szczupłe, ale mogę zdobyć o nim wszystkie informację w ten sposób.

https://api.github.com/users/PanNiebieski

Wpisując do adresu przeglądarki adres https://api.github.com/users/PanNiebieski wysyłasz zapytanie do serwera GitHub na temat użytkownika o nazwie “PanNiebieski”.

To co widzisz w przeglądarce, to właśnie notacja tekstowa JSON. Angular przerobi ten tekst na obiekt.

W tym obiekcie widzimy, że mamy ścieżkę do zdjęcia z awatarem, adres bloga, imię i nazwisko, email i datę utworzenia konta.

Poprzednim razem w Plunker http://plnkr.co/ stworzyliśmy parę kontrolerów i wyświetliliśmy przy ich użyciu dane.

 Plunker

Teraz wiele elementów, które utworzyłem wcześniej nie będzie mi już potrzebne. Po pierwsze usuńmy wszystkie kontrolery, poza “MainController”. Jeśli chodzi o widok HTML elementy pobierające dane z tych kontrolerów nie będą nam też potrzebne.

 Plunker uzupełnienie JavaScript

W kodzie poniżej wysyłamy zapytanie do GitHub API.

var MainController = function($scope, $http) {

    var onRequestCompleted = function(response) {
        $scope.user = response.data;
    }
    $http.get("https://api.github.com/users/PanNiebieski").
        then(onRequestCompleted);
}

Później korzystamy z mechanizmu obietnic.

Do metody“then” przypisujemy funkcję przetrzymywaną w parametrze “onRequestComplete”.

Pozostało jeszcze zmienić składnię strony HTML. Jak widać wykasowałem treść pozostałych kontrolerów.

Obiekt, na którym operujemy nazywa się “user” , gdyż tak go określimy w MainController.

Dalsza zawartość tego obiektu jest określona przez API GitHub.

<body>
    <div ng-app>
        <div ng-controller="MainController">
            <p>Imie i nazwisko :{{user.name}}</p>
            <p>Email : {{user.email}}</p>
            <p>Adress Bloga : {{user.blog}}</p>
            <p>Utworzony : {{user.created_at}}</p>
            <p>Awatar : </p>
            <p>
                <img ng-src="{{user.avatar_url}}" 
                title="{{user.name}}" />
            </p>
        </div>
    </div>
</body>

Uruchamiając stronę, w praktyce możesz zauważyć, że dane nie wyświetlają się natychmiast. To dlatego, że muszą być one najpierw pobrane.

Przy okazji możecie podziwiać moje czoło.

 Plunker rezultat

Co jeśli jednak usługa jest chwilowo niedostępna, albo w ogóle nie działa.

Pobieramy dane z serwera, ale on nie musi zawsze działać.

My z jakiegoś powodu możemy stracić połączenie z Internetem.

Ogólnie mówiąc nie mamy żadnej gwarancji, że dane do nas trafią za każdym razem.

var MainController = function ($scope, $http) {

    var onRequestCompleted = function (response) {
        $scope.user = response.data;
    }

    var onError = function (reason) {
        $scope.error = "Nie można pobrać informacji"
    }

    $http.get("https://api.github.com/users/PanNiebieski").
        then(onRequestCompleted,onError);

}

Nasza obietnica i metoda “then” ma możliwość przesłania funkcji, która się wykona jeśli coś pójdzie nie tak.

Funkcję tę mogę zawrzeć w parametrze “onError”.

W przypadku wystąpienia błędu chcę oczywiście tę informację w jakiś sposób wyświetlić.

<body>
    <div ng-app>
        <div ng-controller="MainController">
            <div>
                <p>{{error}}</p>
            </div>
            <p>Imie i nazwisko :{{user.name}}</p>
            <p>Email : {{user.email}}</p>
            <p>Adress Bloga : {{user.blog}}</p>
            <p>Utworzony : {{user.created_at}}</p>
            <p>Awatar : </p>
            <p>
                <img ng-src="{{user.avatar_url}}" 
                title="{{user.name}}" />
            </p>
        </div>
    </div>
</body>

Jak wymusić błąd pobrania danych. Bardzo prosto. Wystarczy zmienić adres usługi API, do której wywołuję zapytanie.

W praktyce działa to tak.

 Plunker Angular Error

Jak widać wyświetlił mi się napis “Nie można pobrać informacji”.

Następnym razem omówimy moduły.