:sparkles: PWA :sparkles:
Logo

Piotr Kowalski

Organizator WarsawJS , Trener, YouTuber

Szkolenie: AngularJS Podstawy [Relacja Live]

Szkolenie poprowadził Tomasz Sułkowski - developer pracujący w Hexagram. Od 16 miesięcy związany z firmą konsultingową Sages.

Oficjalne logo frameworka AngularJS.

Miejsce szkolenia to siedziba firmy Sages na ul. Nowogrodzka 62c. Więcej o firmie: sages.com.pl/.

Slajdy dostępne pod adresem: slideshare.net/sagespl/podstawy-angularjs.

09:05 - Agenda

  • wprowadzenie / kontekst / narzędzia
  • teoria / demo
  • warsztat
  • teoria / demo
  • warsztat
  • ...
  • Q & A

Korzystamy ze Slacka - IMO komunikator teraźniejszych czasów.
Na początku trochę pytań odnośnie doświadczeń.

Cel: Budujemy aplikację typu SPA

SPA - Single Page Application

Nawigacja w aplikacji typu SPA polega na żonglowaniu hashem w URLu.

Narzędzia

Tomek polecał narzędzia:

  • WebStorm (IDE)
  • Sublime Text 3
  • Atom 1.0
  • Brackets
  • ... Vim?

Ze swojego doświadczenia stwierdził, że po kilku miesiącach korzystania z Submlime Text 3, postanowił przerzucić się na WebStorm, ze względu na lepsze podpowiadanie oraz na poprawianie literówek, które każdy z nas, siłą rzeczy, popełnia.

npm - Node Packaged Modules

  • system zarządzania zależnościami dla "server-side js"
  • zależności opisywane w pliku package.json
  • npm install - instaluje pakiety, których jeszce nie ma w projekcie
  • npm update - sprawdza, czy istnieją nowsze wersje pakietów + instaluje
  • npm install nazwa-pakietu --save-dev - instaluje pakiet, dodaje go do package.json

Aby nie trzymać zależności w projekcie. Dla nowego środowiska wystarczy zainstalować jednym poleceniem biblioteki.

Dodatkowo, możemy określi konkretną wersję którą chcemy zainstalować.
Domyślnie, trzeba by było szukać biblioteki w sieci i ściągać plik na dysk - teraz wystarczy jedno polecenie.

Bower

Instalacja poleceniem npm install -g bower

  • zarządzanie zależnościami dla "client-side js"
  • zależności opisywane w bower.json
  • bower install - instaluje pakiety, których jeszcze nie ma w projekcie
  • bower update - sprawdza, czy istnieją nowsze wersje pakietów + instaluje
  • bower install nazwa-pakietu --save - instaluje pakiet, dodaje go do bower.json
  • pakiety instalowane są do katalogu /bower_components/nazwa-pakietu/... - stamtąd należy je linkować w plikach html

09:30 - Ćwiczenie 1

Stworzenie nowego projektu w WebStorm.

  • ctrl+shift+a - wyszukiwarka wszystkich opcji edytora WebStorm
  • ctrl+shift+o - szukanie plików w projekcie
  • ctrl+e - lista ostatnio otwartych plików

Złota myśl Nauka skrótów jest bardzo pomocna. Umiejętność sprawnego poruszania się w skrótach, pomaga zdecydowanie zmniejszyć czas potrzebny na wykonywanie bieżącej pracy.

Omawianie struktury wygenerowanego seed-a

Kiedy stworzyliśmy nowy projekt typu AngularJS WebStorm stworzył prostą strukturę katalogów wraz z wieloma plikami.

W kolejnym kroku czyścimy boilerplate usuwając e2e-test, index_async.html oraz 2 pliki CSS z html5-boilerplate.

Po wydaniu magicznego polecenia npm install mamy do projektu ściągnięte wszystkie zależności. W pliku package.json w script/postinstall uruchomimy również bower install, więc i biblioteki client-side będą zainstalowane w katalogu app/bower_components.

Gdybyśmy nie mieli żadnego serwera serwującego statyki, w zależnościach mamy wpisany http-server. Jest to prosty serwer napisany w Node.js.

10:00 - Instalujemy Bootstrap

Dzięki poleceniu bower install --save bootstrap instalujemy Bootstrap-a. W zależności Bootstrap jest biblioteka jQuery.

W katalogu app/bower_components znajduje się ściągnięty pełny projekt Bootstrap oraz jQuery.

TIP
Bower zawsze cache-uje sobie biblioteki, aby przy ponownym pobraniu szybko ściągnął kolejny raz zależności.

10:04 - Korzystamy z Bootstrap-a

Dołączamy Bootstrap-a do index.html dorzucając przed plikiem app.css następującą linijkę kodu:

    <link rel="stylesheet" href="bower_components/bootstrap/dist/css/bootstrap.css">

Usuwanie zbędne paczki: bower uninstall angular-mocks.
Dodatkowo usuńmy zbędne komponenty app/components.

10:11 - Prezentacja docelowej aplikacji

Tomek przedstawia aplikację, do którą chcemy dziś napisać. Portal bardzo podobny do ipla.tv lub może bardziej do filmweb.pl. Przeglądanie listy seriali i wchodzimy w szczegóły danego serialu i możemy przeczytać opis. Możemy wyszukiwać dany serial po nazwie, oraz dodać dowolny serial do listy ulubionych.

10:15 - AngularJS

Posłuchamy teraz trochę więcej na temat samej biblioteki AngularJS.
Najbardziej zewnętrzną rzeczą w aplikacji jest moduł. Każdy moduł może posiadać specyficzną konfigurację. Na szkoleniu będziemy korzystali z jednej specyficznej usługi - routing (ui.router).

TIP
Podejście Fat model ma do siebie, że kontrolery powinny być "cienkie", czyli nie zawierały dużo kodu, ale za to modele powinny przechowywać jak najwięcej się da :smiley:

Moduły, struktura aplikacji

Form Follows Function
  • Moduły wskazuję na zależności od zewnętrznych bibliotek
  • Modułu nie separują zawieranych komponentów (brak namespaces)
  • Poszczególne fragmenty aplikacji jako moduły, o hierarchii odzwierciedlonej w strukturze katalogów

TIP
Gdy stworzymy usługę o tej samej nazwie, to zostanie nadpisana poprzednia usługa w innym module o tej samej nazwie.

Routing

ngRoute do jakiegoś czasu był obecny w AngularJS. Jest dosyć prosty.
Lepszym rozwiązaniem jest ui.router.

W ui.router mamy kaskady widoków - każdy widok (kawałek HTMLa) może posiadać dostęp do innego kawałka kodu HTML, bez przeładowania całego globalnego widoku.

ngRoute niestety przeładowuje całą stronę, dzięki czemu korzystanie z aplikacji jest bardzo podobne do typowego przeglądania stron internetowych (mam tu na myśli efekt przeładowania się całej strony).

10:33 - Ćwiczenie 2

Podmiana ngRoute na ui.router (github.com/angular-ui/ui-router).

Instalujemy ui.router poprzez wykonywanie polecenia:
bower install angular-ui-router --save
oraz usuwamy starą paczkę
bower uninstall angular-route --save

11:04 - Ścieżki w aplikacji (ui.router)

Dodajemy katalogi: app/library, app/profile, app/search.

11:12 - Dependency Injection

AngularJS zanalizuje kontrolery, wyciąga nazwy parametrów na podstawie łańcucha znaków, który dostajemy kiedy uruchomimy toString na funkcji.

function MainController($scope, $http) {
    console.log($scope, $http);
}

MainController.toString() // => 'function MainController($scope, $http) { ...'

Na podstawie wyrażenia regularnego AngularJS wyciąga nazwy parametrów, których oczekujemy.

TIP
Gdy dokonamy minifikacji kodu pojawi się problem ze wstrzykiwaniem odpowiednich modułów, ponieważ wszystkie nazwy zmiennych zostaną zmienione na krótkie zaczynając od zwykłych liter. Z pomocą przychodzi ngAnnotate - github.com/olov/ng-annotate.

Dodajemy moduł ui.router.

angular.module('myApp', ['ui.router']).
    config(function ($stateProvider) {
      $stateProvider
          .state('search', {
              url: '/search',
              templateUrl: 'search/search.html'
          });
    });

Dodatkowo podmieniamy w index.html

<!-- Następującą linijkę w pliku index.html: -->
<div ng-view></div>
<!-- Zastępujemy na taką: -->
<div ui-view></div>

Tworzymy strukturę w projekcie - plik app/search/search.html.

Ustawiamy domyślną stronę poprzez $urlRouterProvider

$urlRouterProvider.otherwise('/search');

11:49 - Widok

Kawałki mniejszego HTMLa, które możemy użyć w innym (większym).

11:51 - Controller

Zwykła funkcja JavaScript.

Powiązanie z widokiem odbywa się przez $scope.

TIP
$scope jest to usługa, która jest obiektem. To co zdefiniujemy w tym obiekcie, będzie to od razu dostępne dla widoku (dyrektywy).

11:54 - Dyrektywy

... czyli HTML na sterydach! :smiley:

Możemy użyć na kilka sposobów:

  • element
  • atrybut
  • klasę CSS
  • komentarz

Wbudowane dyrektywy:

  • ng-app
  • ng-init - służy do wykonywania kodu na początku
  • ng-model - służy do prowadzenia interakcji między użytkownikiem a modelem
  • ng-show - gdy wartość będzie truly to kontener się wyświetli (dodaje klasę ng-hide - widoczność poprzez CSS)
  • ng-if - usuwa albo dodaje dany fragment do DOMa
  • ng-repeat - służy do iteracji po tablicy
  • ng-list - podczas prezentacja tablicy jako ciąg znaków, traktuje ten ciąg jako tablicę

two-way data-binding - wiązanie w obie strony, tj: widok aktualizuje model, który od razu jest zmieniony w kontrolerze, ale i w drugą stronę, gdy kontroler zaktualizuje model, będzie od widoczny (najszybciej jak to możliwe) widoku.
Więcej na ten temat na stronie https://docs.angularjs.org/guide/databinding.

TIP
AngularJS promuje deklaratywny styl pisania aplikacji (przeciwieństwo do imperatywnego).

Logika interfejsu jest w HTMLu!

<input type="text" ng-model="flag">

<!-- Pierwotnie: flag=undefined (AngularJS nic nie wyświetli)-->
<!-- Po kliknięciu: flag=true -->
<!-- Po odkliknięciu: flag=false -->

Input jest dyrektywą!

Więcej na temat dyrektyw w dokumentacji: https://docs.angularjs.org/guide/directive.

TIP
Podczas wykonania ng-repeat tablica nie może posiadać duplikatów.

Jeśli jednak chcemy operować na duplikatach trzeba utworzyć specjalną konstrukcję:

<ul>
    <!-- Rozwiązujemy problem duplikatów -->
    <li ng-repeat="name in names track by $index">
        { { name } }
    </li>
</ul>

12:18 - Usługi

Do czego służą usługi?

Miejsce gdzie trzymamy logikę biznesową. Wykonują się w kilku kontrolerów, więc nie ma sensu tego powtarzać. Usługi również służą do tego, aby współdzielić dane miedzy kontrolerami.

Definicja usług na 5 sposobów:

  • .constant() - proste wartości, nie można nadpisywać
  • .value() - proste wartości, można nadpisywać
  • .service() - większa usługa, która może posiadać wiele metod i właściwości
  • .factory() - większa usługa, która zwraca jeden obiekt
  • .provider() - generyczna usługa, bo każda jest de facto providerem

Więcej na temat usług https://docs.angularjs.org/api/ng/service/$http.

12:35 - Ćwiczenie 3

Tworzymy SearchController w katalogu app/search/, wykorzystujemy usługę $http do pobierania listy filmów.

13:07 - Przerwa obiadowa!

14:05 - Prezentacja swoich wyszukiwarek

Rozwiązujemy problem z obrazkami poprzez ng-src.

14:33 - Tworzymy service

Bardzo prosty service operujący na kolekcji dodanych elementów. Przykładowa implementacja:

"use strict";

angular.module('myApp')
    .service('library', function () {
        var library = [];

        this.add = function (item) {
            library.push(item);
        };

        this.getAll = function () {
            // kopia, aby nie tracić tej hermetyzacji
            return library.slice();
        };

        this.has = function (item) {
            return library.indexOf(item) !== -1;
        };

        this.remove = function (item) {
            var index = library.indexOf(item);

            if (index !== -1) {
                library.splice(index, 1);
            }
        };
    });

Jako dodatkowe zajęcie dostałem zapisywanie do localStorage. Udało mi się zrobić w 5 minut :smiley:

Tomasz poleca portal nodeschool.io/pl/ gdzie można podszkolić się z JavaScript.

Aby obserwować jakiś model należy wykonać:

$scope.$watch('query', function (newValue, oldValue) {
    console.log(newValue, oldValue);
});

Na samym początku ładowania aplikacji $watch zostanie uruchomiony i przekazane zostaną mu wartości undefined. Można się przed tym zabezpieczyć wystarczy sprawdzić czy nowa wartość równą się starej, bo tylko na początku obie wartości będą miały tą samo wartość.

15:22 - Dyrektywa ng-model-options

Dzięki tej dyrektywie mamy możliwość skonfigurowania komunikacji pomiędzy widokiem a kontrolerem.

<input type="search" ng-model="query" ng-model-options="{ debounce: 1000 }">

Dzięki takiemu zastosowaniu odciążamy trochę aplikację, dodając lag na zmianę modelu.

Tomasz poleca wtyczkę do Batarang, dzięki której mamy możliwość podglądu modelów analizując DOMa.

15:30 - Directive Definition Object

  • Enkapsulują logikę związaną z zachowaniem
  • Tworzą widgety - małe aplikacje, klocki z których budujemy większe fragmenty

Jako zadanie domowe warto zrobić dyrektywę dla przycisków "Dodaj" i "Usuń".

16:25 - Filtry

Umożliwiają przekształcanie danych w trakcje przejścia ze $scope do widoku bez zmieniania oryginalnej wartości.

Jest około 7 standardowych filtrów. Ta mała liczba wynika ze względu na prostotę dodawania swoich.

Od AngularJS 1.3 mamy w filtrach pure function, czyli dla takich samych parametrów mamy te same wyjście, tym samym biblioteka zapamiętuje (proces memoizacja) wynik dla tych samych parametrów.

16:39 - Formularze

TIP
Koniecznie trzeba ustawiać nazwy dla znacznika form, ponieważ będzie on pod tą nazwą dostępny w scope.

Stany formularza

  • $valid - bez błędów
  • $invalid - z błędami
  • $pristine - nienaruszony
  • $dirty - zmodyfikowany

16:57 - Dobre praktyki

17:08 - Kończymy na dziś!

Podziękowanie dla Tomka za całodniowe szkolenie :smiley:

Tagi: workshop

4 dni wcześniej napisałem: DevMeetings: ECMAScript 6: Kraków następne dnia napisałem: Jak założyć bloga korzystając z Jekyll?

Możesz osadzić kod wykorzystując: <pre><code class="{language}"></code></pre>