70-480 – Wstęp do HTML5, JavaScript i CSS3

70-480

Jako, że zaczynam przygotowania do egzaminu 70-480, to potraktuję to miejsce jako zbiór swoich notatek oraz postaram się w ten sposób stworzyć materiał, który wykorzystać będzie mógł każdy, kto spróbuje swych sił z HTML5, JavaScript oraz CSS3.

Egzamin 70-480 ujęty jest w ścieżce certyfikacyjnej Microsoft i ma na celu zbadanie umiejętności zdającego w obszarach wykorzystania HTML5, CSS3 oraz języka JavaScript. Jest także częścią ścieżek:  MCSD: Web ApplicationsMicrosoft Specialist Certification. Zakres egzaminu określiłbym raczej jako podstawowy dla doświadczonej osoby, ale z racji darmowej możliwości wykorzystania vouchera, chętnie poświęcę trochę czasu i przygotuję się do niego, tworząc przy okazji gotowe kompendium.

Pełen zakres egzaminu oraz poszczególne artykuły można znaleźć na stronie: Egzamin 70-480 – Programming in HTML5 with JavaScript and CSS3

Postaram się poza tym, by wpisy były zwięzłe i opisywały tylko konkretne informacje. Tym samym zapraszam Was do całej ich serii.

AngularJS #8 – Factory vs Service vs Provider

AngularJS



AngularJS daje nam możliwość pisania kodu na wiele różnych sposobów. Jedną z tendencji jaką zauważam na StackOverflow jest to, że ludzie starają się upchać do swoich kontrolerów wszystko co tylko możliwe – łącznie z logiką biznesową, pobieraniem / zapisywaniem danych, operacjach na DOM, czy przetwarzaniu wielkich struktur danych. Jest to wprawdzie domena tych mniej doświadczonych, jednak warto by każdy starał się odchudzać swoje kontrolery już na etapie pisania pierwszego kodu, a nie na etapie refaktoringu lub później (albo w ogóle!).

Kontrolery

Kontrolery w AngularJS mają to do siebie, że tworzone są (umieszczane w pamięci przeglądarki) w ramach tego jak są potrzebne i usuwane, gdy przestają być używane. Wyobraźmy sobie przechodzenie pomiędzy różnymi stronami naszej aplikacji, pomiędzy różnymi definicjami routingu, gdzie dla każdej strony wywoływany jest osobny kontroler. Następnie wyobraźmy sobie, że wszystkie elementy w kontrolerach tworzone i usuwane są za każdym takim przejściem ze strony do strony. Jest to niebywałe marnotrastwo zasobów, co wpływa także na wydajność pisanej przez nas aplikacji. Całą tą logikę odpowiedzialną chociażby za pobieranie danych lub ich zapisywanie po stronie API (backendu) jesteśmy w stanie przenieść do osobnych serwisów, które to wstrzyknięte do naszego kontrolera pozwolą zrealizować dokładnie taką samą funkcjonalność. Serwisy mają tą przewagę, że tworzone są jednorazowo (jako singletony) i wstrzykiwane mogą być jako zależność do wielu kontrolerów.

Factory vs Service vs Provider

Problem może pojawić się na etapie wyboru odpowiedniej drogi, która pozwoli nam zrealizować daną funkcjonalność. AngularJS daje nam obecnie trzy sposoby na odchudzenie naszych kontrolerów poprzez użycie:

  • Factory
  • Service
  • Provider

Poniżej postaram się omówić każdy z nich oraz wskazać różnice, które mogą zadecydować o konkretnym wyborze. Przykłady będą bajecznie proste, więc z pewnością każdy poradzi sobie z ich przyswojeniem. Celowo nie wykorzystuję tutaj $http, czy $resource, by nie komplikować i zaciemniać kodu. Znając oba mechanizmy możecie posłużyć się nimi do zbudowania pełnoprawnego kodu serwisu, który obsługiwać będzie logikę biznesową Waszej aplikacji. Przechodząc jednak do konkretów..

1 ) Factory

Factory to w zasadzie najprostsza wersja serwisów w AngularJS. Tworząc factory, tworzymy de facto obiekt z polami w formie zwykłych zmiennych lub funkcji, który następnie zwracamy poprzez użycie return. Wstrzyknięte do kontrolera factory jest dokładnie takim prostym obiektem. Posłużę się przykładem, który lepiej zilustruje to co mam na myśli.

[wp-js-fiddle url="https://jsfiddle.net/mrzepinski/69YQ8/1/" style="width:100%;height:400px;border:solid #4173A0 1px;"]

Spójrzcie od razu na zakładkę JavaScript. Stworzyłem tam naiwny kontroler, którego jedynym zadaniem jest ustawienie nazwy użytkownika poprzez wywołanie metody setUsername() serwisu User wstrzykniętego jako dependency do kontrolera oraz wywołanie metody sayHello() tegoż serwisu w celu pobrania wiadomości powitalnej dla ustawionej nazwy użytkownika.

Poza kontrolerem zdefiniowany został serwis User typu factory. W ciele tego serwisu mamy trzy zmienne lokalne (_username, _setUsername, _sayHello), które widoczne są tylko w ramach tego serwisu. Następnie zwracany jest nowy obiekt za pomocą polecenia return z dwoma polami (setUsername, sayHello), do których przypisane zostają referencje zmiennych lokalnych (funkcji), odpowiednio _setUsername oraz _sayHello. Równie dobrze jednak, nasz serwis factory mógłby wyglądać tak:

[wp-js-fiddle url="https://jsfiddle.net/mrzepinski/69YQ8/2/" style="width:100%;height:400px;border:solid #4173A0 1px;"]

Ograniczamy się w tym momencie do jednej zmiennej lokalnej w kontrolerze User.

Poprzez wstrzyknięcie factory User do kontrolera, otrzymujemy w nim dostęp do pól zwróconego obiektu. Działanie jest tak proste, że nie zamierzam tego komplikować kolejnymi wyjaśnieniami.

2) Service

Kolejny serwis nazwany został dosłownie Service. W porównaniu do FactoryService tworzony jest na zasadzie użycia słowa new, a następnie zostaje wstrzyknięty do kontrolera. Użycie konstruktora (new) powoduje, że wszystkie widoczne w serwisie zmienne przypisane muszą zostać do słowa this, które widoczne jest po wstrzyknięciu serwisu do kontrolera. Spójrzcie na ten sam przykład, ale z wykorzystaniem Service.

[wp-js-fiddle url="https://jsfiddle.net/mrzepinski/69YQ8/3/" style="width:100%;height:400px;border:solid #4173A0 1px;"]

Widać wyraźnie, że kod po stronie kontrolera pozostał taki sam. Serwis natomiast wygląda nieco inaczej. Nie ma już słowa return i zwracanego w ten sposób obiektu z metodami setUsername oraz sayHello. Zamiast tego, metody te przypisane zostały do słowa kluczowego this, które zwrócone zostanie do kontrolera w ramach wywołania konstruktora przy użyciu new przez $injector.

3) Provider

Provider jest jedynym serwisem, który użyty może być w ramach config naszej aplikacji. Dzięki temu jesteśmy w stanie dokonać ustawień naszego serwisu jeszcze zanim zostanie on wstrzyknięty i użyty w kontrolerze. Struktura provider jest nieco rozdmuchana, ale w gruncie rzeczy przypomina on factory oraz service. Poniżej ciągle ten sam przykład, ale z wykorzystaniem provider.

[wp-js-fiddle url="https://jsfiddle.net/mrzepinski/69YQ8/4/" style="width:100%;height:400px;border:solid #4173A0 1px;"]

Zmian jest sporo. Na samym końcu zobaczyć możecie nową sekcję: config. Służy ona do ustawiania parametrów naszej aplikacji, a w tym wypadku do ustawienia pola naszego serwisu. W samym provider mamy teraz zmienną _username przypisaną do słowa this i tylko takie zmienne widoczne są z poziomu config aplikacji. Następnie do this przypisana zostaje funkcja $get, która z kolei zwraca nam prosty obiekt za pomocą słowa return do kontrolera. Tylko obiekt zwrócony przez funkcję $get naszego providera widoczny jest po tej drugiej stronie (kontrolerze). W kontrolerze ubyło ustawianie nazwy użytkownika, która przeniesiona została do części config. Warto zauważyć, że do ciała funkcji config wstrzykiwany jest UserProvider, a nie User. Zapamiętajcie, że w ten sposób możemy dobrać się do pól przypisanych do this naszego providera. Gdybyśmy nasz provider nazywał się np. myProvider, to do config musielibyśmy wstrzyknąć myProviderProvider. Za każdym razem jest to dodanie słowa Provider do oryginalnej nazwy. Pozostaje również zapamiętać, że tylko serwis provider pozwala nam na ustawienie zmiennych w sekcji config aplikacji.

Krótko podsumowując

Tym oto prostym sposobem udało mi się (mam nadzieję) pokazać zasadnicze różnice pomiędzy różnymi typami serwisów w AngularJS. Zapraszam tym samym do podzielenia się swoimi wnioskami w komentarzach oraz do odchudzania swoich kontrolerów.

AngularJS #7 – HTML na sterydach – wprowadzenie do dyrektyw

AngularJS



AngularJS nie byłby bez dyrektyw tym samym frameworkiem. To właśnie dyrektywy są absolutną przewagą AngularJS. Tak jak w tytule – użycie dyrektyw, to HTML na sterydach. Dzięki nim jesteśmy w stanie nauczyć nasz HTML nowych sztuczek.

Dyrektywa

Czym jest więc wspomniana dyrektywa? W poprzednich wpisach kilka razy wspominałem o dodatkowych elementach, atrybutach, komentarzach HTML oraz klasach CSS, które możemy używać w HTML dzięki wykorzystaniu AngularJS. Te dodatkowe rzeczy, to nic innego jak dyrektywy. AngularJS w fazie kompilacji ($compile) skanuje drzewo DOM naszego dokumentu HTML, a następnie w miejsce wystąpień dyrektyw podpina funkcjonalności na poziomie samego DOM. Owe funkcjonalności mają zastosowanie na poziomie elementu, dla którego zdefiniowaliśmy dyrektywę oraz wszystkich jego dzieci. Dyrektywy pozwalają w ten sposób budować reużywalne komponenty, które pozwalają manipulować drzewem DOM oraz dostarczać mu nowych funkcjonalności.

Przykłady istniejących dyrektyw znajdziecie praktycznie w każdym miejscu. ng-appng-controllerng-bind istnieją w AngularJS. W poprzednich wpisach wykorzystałem chociażby dyrektywę ng-repeat, która pozwoliła mi zbudować dynamiczną listę w oparciu o kolekcję obiektów. Dyrektywy są najczęściej wykorzystywanym elementem AngularJS i stanowią o jego sile i przewadze nad innymi frameworkami JavaScript.

Opcje

Dyrektywy tworzone mogą być na kilka różnych sposobów. Posiadają także szereg parametrów konfiguracyjnych, które odpowiadają za samo funkcjonowanie oraz użycie dyrektyw. Przejdźmy przez większość z nich.

restrict

Jak już wcześniej wspomniałem – dyrektywy możemy wywoływać w HTML na kilka sposobów. Określa to parametr restrict, który przyjmuje wartości:

restrict: 'A'
<div my-directive></div>
restrict: 'C'
<div class="my-directive: expression;"></div>
restrict: 'E'
<my-directive></my-directive>
restrict: 'M'
<!-- directive: my-directive expression -->

Możemy oczywiście podać wszystkie wartości jednocześnie: restrict: ‘EMAC’. Najbardziej popularne i chyba najrozsądniejsze jest wykorzystanie atrybutów oraz elementów HTML jako sposobu wywołań dyrektyw. Najlepiej radzą sobie z tym również przeglądarki.

template

Kolejnym elementem jest atrybut template, który pozwala nam zdefiniować szablon, który wykorzystywać będzie nasza dyrektywa. Dzięki temu możemy bindować dane przekazywane do dyrektywy lub generowane przez kontroler (patrz niżej) samej dyrektywy.

template: '<div>My extra template is here</div>'

templateUrl

Szablony umieszczać możemy również w osobnych plikach. Nierzadko będą one rozbudowane, więc tym łatwiej będzie nam je trzymać w osobnym pliku HTML, gdzie nasze IDE pozwoli nam też podpowiadać składnię, niżeli pisać szablon w postaci łańcucha znaków w JavaScript. Szablony zdefiniowane w ten sposób ładowane są asynchronicznie i cachowane.

templateUrl: 'templates/my-extra-template.html'

controller

Dyrektywy posiadać mogą własne, lokalne kontrolery, gdzie definiować możemy metody operujące na danych. Pozwala to budować logikę dyrektywy, którą następnie możemy używać chociażby w szablonie.

compile

Atrybut dyrektywy, który definiuje jej działanie w czasie kompilacji – jeszcze przed podpięciem samej dyrektywy do drzewa DOM. Faza compile zwraca funkcję link (patrz niżej), pozwalającą na bindowanie logiki dla elementu w drzewie DOM.

link

Finalne bindowanie logiki dyrektywy dla elementu w drzewie DOM. Jest wynikiem fazy kompilacji następującej przed samym linkowaniem.

require

Pozwala nam określić zależności w postaci innych dyrektyw, które wymagane są do działania naszej dyrektywy. Spójrzmy na definicję dyrektywy:

app.directive('myDirective', function () {
    return {
        restrict: 'A',
        require: '^ngModel'
    };
});

oraz przykład jej wywołania:

<div my-directive ng-model="city"></div>

Gdyby zabrakło tutaj wywołania ng-model, to otrzymalibyśmy błąd mówiący nam o tym fakcie.

Zauważyliście zapewne znak ^ przed nazwą ngModel. Informuje on kompilator AngularJS by szukać wywołania dyrektywy ngModel także poza elementem, dla którego zdefiniowano dyrektywę myDirective.

Istnieje również opcja ?, która spowoduje, że w przypadku braku zdefiniowanej zależności nie otrzymamy błędu kompilacji dyrektywy.

scope

Jak możecie się domyślać – jest to lokalny scope w naszej dyrektywie. Wywołując dyrektywę w HTML możemy do niej przekazywać różne parametry.

Spójrzmy na kawałek kodu:

scope: {
    param1: '@',  // parametr przekazywany przez wartosc (one-way binding)
    param2: '=',  // parametr przekazywany przez referencje (two-way binding)
    param3: '&'   // wyrazenie, ktore moze zostac wywolane w ciele dyrektywy
}

Pozwoli nam to zdefiniować dyrektywę w następujący sposób:

<div my-directive param1="{{ onlyValue }}" param2="toWayBindingByReference" param3="functionInvokedInDirective()"></div>

replace

replace: true

Pozwala na zamianę ciała elementu, dla którego definiujemy w całości przez szablon dyrektywy.

transclude

Możemy w ten sposób pobrać zawartość elementu, dla którego definiujemy dyrektywę, a następnie przekazać ją do szablonu dyrektywy.

transclude: true

Wyobraźmy sobie HTML w postaci:

<div my-directive>
    <p>To template please!</p>
</div>

Wykorzystanie opcji transclude w dyrektywie pozwoli nam na pobranie <p>To template please!</p> oraz przekazanie do szablonu w następujący sposób:

app.directive('myDirective', function () {
    return {
        restrict: 'A',
        template: '<div ng-transclude></div>',
        transclude: true
    };
});

Tym samym paragraf p przekazany zostanie do div szablonu dyrektywy.

Pierwsza dyrektywa

Poniżej przykład budowy oraz wykorzystania dyrektywy, która pozwalać będzie na wstawienie w dane miejsce dokumentu HTML reużywalnego komponentu w postaci listy z tytułem.

[wp-js-fiddle url="https://jsfiddle.net/mrzepinski/Ggur3/2/" style="width:100%;height:400px;border:solid #4173A0 1px;"]

Egghead

“First Directive”

[youtube_sc url=”https://www.youtube.com/watch?v=xoIHkM4KpHM”]

“Directive Restrictions”

[youtube_sc url=”https://www.youtube.com/watch?v=AoDh1T_0Obg”]

I na koniec

Mam nadzieję, że starczy mi czasu i determinacji na kolejne wpisy o AngularJS. Na chwilę obecną nie jestem w stanie przewidzieć o czym będzie mowa następnym razem. Przewiduję, że natchnie mnie w pewnym momencie na napisanie bardziej praktycznego wpisu. Sam temat jest z pewnością wart uwagi.

AngularJS #6 – Karma – pierwszy test

AngularJS



Kolejnym wpisem miało być rozszerzenie o filtrach, ale uznałem, że jest tam zbyt mało materiału, by robić z tego osobny element całego cyklu o AngularJS. Sam temat filtrów jest poza tym na tyle prosty, że nie warto poświęcać na niego zbyt wiele czasu. Znacznie bardziej należałoby się skupić na elemencie testowania aplikacji i dlatego też chciałbym Was wprowadzić w świat Jasmine i Karma.

Karma

Karma jest narzędziem, które pozwala uruchamiać testy kodu JavaScript pod różnymi przeglądarkami, a w zasadzie ich emulowanym środowiskiem. Karma nie jest pełnoprawnym frameworkiem do testowania, a jedynie rusztowaniem, na którego bazie zbudować możemy pełny stack testujący JavaScript. Karma zbudowana jest w oparciu o serwer Node.js oraz technologię Socket.io. Pozwala na wykonywanie testów w różnych środowiskach pracy (deweloperskim, testowym, produkcyjnym itd.), a ponadto wykonuje wszystkie testy w separacji od kodu właściwego. Pozwala także na wykonywanie testów pod różnymi przeglądarkami jednocześnie. W połączeniu z Istanbul, który to potrafi wygenerować i pokazać nam pokrycie naszego kodu testami, Karma stanowi pełnoprawne środowisko testowe, które ułatwia nam, a w zasadzie pozwala na szybkie i bezproblemowe testowanie kodu JavaScript.

Pełny opis instalacji oraz konfiguracji znajdziecie na oficjalnej stronie projektu. Znajduje się tam także film, który bardzo trafnie prezentuje możliwości jakie daje nam Karma.

Jasmine

Spośród kilku frameworków do testowania kodu JavaScript, miałem do tej pory okazję wykorzystywać właśnie Jasmine. Jasmine, to behavior-driven development framework, który pozwala na pisanie naszych testów w sposób bardzo opisowy, a ponadto świetnie integruje się ze środowiskiem Karma. Nie jest on zależny od żadnego frameworka JavaScript i nie wymaga także drzewa DOM do działania. Jasmine pozwala nie tylko na pisanie testów jednostkowych, ale również tak zwanych testów e2e. Kilkadziesiąt przykładów znajdziecie na stronie oficjalnej i w zasadzie nie pozostaje nic innego jak zacząć pisać testy!

Główny konkurent JasmineMocha jest nieco bardziej rozbudowany i dojrzały, ale “próg wejścia” jest także nieco większy. Jest jeszcze QUnit, który używany jest w projektach jQuery, jQuery UI oraz jQuery Mobile, ale nie cieszy się taką popularnością community jak pozostałe dwa.

Let’s write some code!

Nie będę tutaj opisywał jak skonfigurować sobie Karmę oraz Jasmine by działały razem, bo jest to świetnie opisane oraz pokazane na stronach oficjalnych obu narzędzi.

Przypuśćmy zatem, że chcemy przetestować działanie metody w naszym kontrolerze. Niech będzie to przykład metody, która po wykonaniu funkcji sayHello() zmienia wartość parametru name w $scope kontrolera APP.ApplicationCtrl na ‘World’.

'use strict';

var APP = angular.module('APP', []);

APP.ApplicationCtrl = function ($scope) {

    $scope.name = '';

    $scope.sayHello = function () {
        $scope.name = 'World';
    };

};

Klasa testowa wyglądać będzie następująco:

'use strict';

describe('APP.ApplicationCtrl', function () {

    var scope;

    // mockujemy nasz modul APP
    beforeEach(angular.mock.module('APP'));
    // mockujemy kontroler ApplicationCtrl
    // i przekazujemy do niego mock $scope utworzony na podstawie $rootScope
    beforeEach(angular.mock.inject(function ($rootScope, $controller) {
        // tworzymy pusty scope
        scope = $rootScope.$new();
        // tworzymy instancje kontrolera i przekazujemy do niego pusty $scope
        $controller('ApplicationCtrl', { $scope: scope });
    }));

    // .. i testujemy
    it('should set new value for $scope.name', function () {
        // having
        scope.name = '';

        // when
        expect(scope.name).toBe('');
        scope.sayHello();

        // then
        expect(scope.name).toBe('World');
    });

});

Wykonanie powyższego testu zwróci nam oczywiście pozytywny wynik. Tym oto prostym sposobem przetestowaliśmy banalną metodę naszego kontrolera.

Jasmine zawiera szereg predefiniowanych metod oraz asercji do testowania naszego kodu. Jesteśmy w stanie na przykład sprawdzić, czy dana metoda wykonała się w cyklu wykonywania innej z metod w naszym kontrolerze, a na dodatek sprawdzić, czy wykonała się określoną ilość razy. Jesteśmy w stanie porównywać całe kolekcje pod względem zawartości, czy emulować zapytania HTTP. Zachęcam do przyjrzenia się dokumentacji i własnych prób.

I na koniec jak zawsze http://egghead.io i prezentacja Karmy oraz Jasmine na równie prostym przykładzie.

[youtube_sc url=”https://www.youtube.com/watch?v=wFYID8eYQLs”]

AngularJS #5 – ng-repeat

AngularJS



W poprzednim wpisie wprowadziłem Was w tematykę filtrów w AngularJS. Mocno powiązanym elementem jest dyrektywa ngRepeat, która pozwala na iterowanie po kolekcji elementów oraz ich wyświetlanie i / lub filtrowanie.

Wyobraźmy sobie znany pewnie wszystkich mechanizm foreach znany z innych języków programowania. Użycie dyrektywy ng-repeat pozwala właśnie na zbudowanie iteratora dla zdefiniowanej kolekcji elementów. Całość jest banalnie prosta w użyciu, a sama dyrektywa ngRepeat posiada kilka wbudowanych wartości, które możemy użyć w ramach iterowanej kolecji. W oficjalnej dokumentacji AngularJS przedstawiona została tabela opisująca te wartości.

Przykład użycia bez filtrowania:

[wp-js-fiddle url="https://jsfiddle.net/mrzepinski/EGW5w/7/" style="width:100%;height:400px;border:solid #4173A0 1px;"]

Dzięki tym kilku linijkom w HTML jesteśmy w stanie wyświetlić wszystkie elementy z tablicy $scope.cities zdefiniowanej w kontrolerze.

Przykład użycia z filtrowaniem wyników:

[wp-js-fiddle url="https://jsfiddle.net/mrzepinski/EGW5w/9/" style="width:100%;height:400px;border:solid #4173A0 1px;"]

By filtrować wylistowane wyniki wystarczyło dodać nowe pole input nad listą oraz zdefiniować dla niego dyrektywę ng-model. Następnie w wywołaniu ng-repeat dodałem parametr filter z nazwą ng-model zdefiniowanego na pola input. Całość działa bez największych problemów. Czegóż chcieć więcej?

Odpowiednik http://egghead.io

[youtube_sc url=”https://www.youtube.com/watch?v=bLohP9mh8ks”]

AngularJS #4 – Wprowadzenie do filtrów

AngularJS



W wyniku przedświątecznej gorączki i mojego “niedoczasu” nie dałem rady postarać się o kolejny wpis w zeszłym tygodniu. Tym razem chciałbym zrobić mały wstęp do filtrów w AngularJS.

W planach na kolejne artykuły o AngularJS są dyrektywy, serwisy, providery, factory oraz wiele innych, ale warto także poznać te podstawowe mechanizmy. Jednym z nich jest własnie serwis $filter lub jak kto woli ngFilter. Filtrów, tych wbudowanych, jak i tych własnych używać możemy po stronie widoków w naszym HTML, ale zarówno w kontrolerach. Służą one do modyfikowania wartości zdefiniowanych w $scope lub właśnie filtrowania kolekcji bez wpływu na ich rzeczywistą wartość.W widokach ich użycie sprowadza się do postawienia pipeline zaraz za wartością, po którym podajemy nazwę filtra, który chcemy wykorzystać. W samych kontrolerach jest to wstrzykiwany serwis $filter, który pozwala na wywołanie konkretnego filtra poprzez parametry funkcji.

Użycie filtrów przedstawia się następująco:

[wp-js-fiddle url="https://jsfiddle.net/mrzepinski/EGW5w/5/" style="width:100%;height:400px;border:solid #4173A0 1px;"]

AngularJS posiada listę wbudowanych filtrów, które możemy używać wraz z samym tylko frameworkim. Nie jest ona imponująca, ale twórcy dali nam mechanizm do tworzenia własnych filtrów, który często się przydaje podczas pisani aplikacji z wykorzystaniem AngularJS.

Napiszę tym samym prosty filtr, który pozwoli dzielić wpisaną w pole input wartość na pojedyncze znaki i wyświetlać je z podkreśleniem jako separatorem.

[wp-js-fiddle url="https://jsfiddle.net/mrzepinski/EGW5w/6/" style="width:100%;height:400px;border:solid #4173A0 1px;"]

Tym prostym sposobem możemy pisać własne transformery, dekoratory, czy po prostu filtry.

Zapraszam jednocześnie do obejrzenia kolejnego odcinka z http://egghead.io

[youtube_sc url=”https://www.youtube.com/watch?v=FX5TwV2ZKqc”]

AngularJS #3 – Pierwsza metoda w naszym $scope

AngularJS



W poprzednim wpisie opisywałem zasadę działania dyrektywy ng-controller obejmującej zakres HTML, który otoczony jest przez element, na którym następuje wywołanie owej dyrektywy. Sama wartość dyrektywy wskazuje na kontroler w JavaScript, który odpowiada za jej działanie. W kontrolerze można tworzyć zmienne oraz metody, które dostępne są po stronie HTML.

Zmienna

Najprostszą formą wykorzystania kontrolera jest utworzenie zmiennej, która przypisana jest do $scope. Sam $scope wstrzykiwany jest do kontrolera poprzez argument funkcji. Jako, że jest to element obsługiwany bezpośrednio przez kompilator AngularJS wystarczy, że użyjemy nazwy $scope i tym samym Angular wie, że należy w tym miejscu posłużyć się serwisem $injector do utworzenia nowego $scope, który dziedziczy po $rootScope (dokładny opis znajduje się w oficjalnej dokumentacji AngularJS).

Posłużę się tutaj przykładem z poprzednich wpisów. Tworzymy kontroler APP.ApplicationCtrl (to pełna nazwa, którą używamy po stronie HTML), gdzie zdefiniowana zostaje zmienna name w $scope kontrolera. Następnie jest ona używa w postaci wywołania {{ name }} w HTML w ramach konkretnego div, gdzie zdefiniowany został kontroler ng-controller=”APP.ApplicationCtrl”. $scope jest w tym momencie jakby naszą przestrzenią globalną (dla div), w której widoczne są wszystkie zdefiniowane zmienne lub funkcje / metody. Zamiast więc pisać {{ $scope.name }} wystarczy po prostu {{ name }}.

[wp-js-fiddle url="https://jsfiddle.net/mrzepinski/snL46/" style="width:100%;height:400px;border:solid #4173A0 1px;"]

Metoda

Kolejnym krokiem jest zdefiniowanie w naszym $scope kontrolera – konkretnej funkcjonalności w postaci metody. Metoda ta będzie niczym więcej niż funkcją … przypisaną do zmiennej w $scope. Stworzyłem tym samym w kontrolerze funkcję sayHelloWorld, która pod zmienną $scope.name podstawia nową wartość. W samym HTML dodałem button, w którym to użyłem dyrektywy ng-click i jako jej parametr przekazuję wywołanie funkcji sayHelloWorld(). W tym miejscu nie używam klamer {{ … }} ponieważ przekazują wywołanie funkcji bezpośrednio do dyrektywy ngClick. Tym oto prostym sposobem nasza mini aplikacja otrzymała pierwszą funkcjonalność.

[wp-js-fiddle url="https://jsfiddle.net/mrzepinski/EGW5w/3/" style="width:100%;height:400px;border:solid #4173A0 1px;"]

Dodajmy dwie kolejne funkcje, które zaktualizują wartość zmiennej name. Warto przy tym zauważyć, że nasz widok HTML aktualizuje się automatycznie. Nie wymaga to odświeżania strony, a ilość kodu JavaScript, który musimy napisać także ogranicza się do minimum.

[wp-js-fiddle url="https://jsfiddle.net/mrzepinski/EGW5w/4/" style="width:100%;height:400px;border:solid #4173A0 1px;"]

Przykład tworzenia i użycia

Po bardziej rozbudowany przykład odsyłam (jak zawsze) do kolejnego filmu z http://egghead.io

[youtube_sc url=”https://www.youtube.com/watch?v=Powr9vzqMac”]

AngularJS #2 – ng-controller

AngularJS



Muszę przyznać, że AngularJS uczę się dopiero od dwóch miesięcy. Do tej pory używałem jedynie czystego JavaScript i jQuery. Używałem to dobre określenie, bo daleko mi do prawdziwego web dewelopera. Projekt, w którym mam szczęście uczestniczyć łączy Javowy backend z single app, która pisana jest właśnie w AngularJS. Stąd powstał pomysł na niniejszy “kurs” (to za dużo powiedziane). Dla Was (mam nadzieję) będzie to szansa na poznanie AngularJS, a dla mnie możliwość by nauczyć się go lepiej. Nic tak nie pomaga przyswajać wiedzy jak uczenie innych.

Przyznam się bez bicia, że rozkład jazdy konstruuję na bazie materiałów w sieci (polecam: http://egghead.io/). Poza dzieleniem się własnymi doświadczeniami, mam zamiar przemycać co nieco od dużo bardziej doświadczonych deweloperów, a czasami i samych twórców AngularJS.

Przeczytałem gdzieś, że “AngularJS, to w końcu JavaScript bez bólu”. Dwa miesiące wystarczyły mi by się o tym przekonać i mam nadzieję, że uda mi się Wam to pokazać.

ng-controller

Przepraszam za przydługi wstęp. Przechodzę czym prędzej do tematu dzisiejszego wpisu. W poprzednim była już mowa o $scope i pierwszy kontroler AngularJS.

[wp-js-fiddle url="https://jsfiddle.net/mrzepinski/snL46/7/" style="width:100%;height:400px;border:solid #4173A0 1px;"]

Tworzenie widoku bez separacji HTML, CSS i JavaScript byłoby trudne. Wykorzystanie jedynie podstawowych elementów AngularJS także nie dawałoby nam wiele. Wplecenie w to wszystko własnej logiki biznesowej oraz dodatkowych funkcjonalności byłoby praktycznie niewykonalne bez kontrolerów, które pozwalają tworzyć odpowiednie warstwy ($scope) do zarządzania naszym widokiem.

Z pomocą przychodzi nam dyrektywa (o tym później) ngController, którą udostępnia nam sam AngularJS, a która to odpowiedzialna jest za budowę warstwy MVC (Model – View – Controller). W oficjalnej dokumentacji czytamy:

The ngController directive attaches a controller class to the view. This is a key aspect of how angular supports the principles behind the Model-View-Controller design pattern.

MVC components in angular:
– Model — The Model is scope properties; scopes are attached to the DOM where scope properties are accessed through bindings.
– View — The template (HTML with data bindings) that is rendered into the View.
– Controller — The ngController directive specifies a Controller class; the class contains business logic behind the application to decorate the scope with functions and values.

Jeżeli czytacie o AngularJS, to z pewnością wiecie też czym jest MVC i nie wymaga to większego komentarza.

Twórcy piszą także o aspekcie wykorzystania kontrolerów w routingu ($route – o tym także będzie potem) i ostrzegają przed często popełnianym błędem, w którym to po zdefiniowaniu kontrolera w naszym configu $route nie ma już potrzeby definiowania kontrolera po stronie HTML w postaci dyrektywy ng-controller. Jeżeli ktoś popełni ową gafę, to jego kontroler zostanie wstrzyknięty dwukrotnie, co na pewno nie jest pożądane.

$scope

Jak większość (wszystkie?) dyrektyw w AngularJS, również ngController tworzy swój własny $scope, czyli przestrzeń, w której widoczne są wszystkie zmienne oraz metody zdefiniowane w kontrolerze, który podany został jako argument dyrektywy. Jest to kolejna warstwa naszej aplikacji. Definiując przykładowo nasz kontroler dla atrybutu <div> w HTML, $scope utworzony zostanie dla wszystkich elementów znajdujących się pomiędzy <div> … </div>. Tym samym wszystkie kontrolery utworzone wewnątrz tej struktury “widzieć” będą metody oraz zmienne utworzone w $scope nadrzędnego kontrolera. W drugą stronę to już tak nie działa. Kontroler nadrzędny nie będzie miał dostępu do logiki utworzonej w swoim kontrolerze-dziecku. Możemy sobie wyobrazić dziedziczenie w statycznie typowanych językach, jednak to nie to samo.

Przykłady

Świetnie oddane zostały przykłady tworzenia prostego kontrolera na oficjalnej stronie dyrektywy: ngController. Nie zrobiłbym tego lepiej, dlatego odsyłam Was właśnie tam (co będę pewnie robił częściej, bo dokumentacja jest naprawdę dobra i ciągle się rozwija / rozrasta). Jeżeli komuś mało, to jest kolejna lekcja poświęcona temu tematowi na http://egghead.io/:

[youtube_sc url=”https://www.youtube.com/watch?v=MEmC0QH8ATQ”]