Mateusz Uherek
Agenda AngularJS REST-owe API w aplikacji Seam Komunikacja AngularJS z serwerem RESTEasy (wbudowanym w serwer JBoss) Przykłady aplikacji wykorzystujących omówione technologie
ZACZYNAMY… 3..2..1..
BUUUM! AngularJS JavaScript SPA MVC Directive Scope Filter Data-Binding Directive View jqLite Scope Service Local Storage Factory Filter BUUUM! Module Dependency Injection Controller Routing JavaScript Validation SPA JSON
???
Co to ten AngularJS ? AngularJS jest w 100% javascript-owym framework-iem (SPA – Single Page Appliction) działającym po stronie klienckiej stworzonym przez Google, który kompatybilny jest z przeglądarkami desktop-owymi oraz mobilnymi. Z racji swojej wielkości często mylnie nazywany biblioteką. Umożliwia wdrożenie wzorca MVC (Model-View-Controller). Jedną z rzeczy, którą od razu wyróżnia jest to, że posiada własny kompilator HTML, przez możemy nauczyć go (html-a) nowych sztuczek.
http://angularjs.org
Pobieramy Angularjs ze strony domowej http://angularjs.org Pobieramy plik js w najnowszej wersji tutaj! Po pobraniu +1 do magii Angulara
Zaczynamy… Plik html $scope to element łączący (klej) między widokiem a kontrolerem Kod js mający dostęp do $scope i zarządzający nim
Dyrektywy (Directive) Uczą HTML nowych trików NASZE WŁASNE!!! +10 do magii Angulara ng-app ng-show ng-model ng-bind
Połączmy to co wiemy w całość A teraz to co misie lubią najbardziej.. Miodzio kodzik!
Magia angulara.. <html> <head> <script src="../angular-1.2.0.min.js"></script> <script> function PierwszyKontroler($scope){ $scope.powitanie = 'Hello AngularJS'; } </script> </head> <body ng-app> <div ng-controller="PierwszyKontroler"> <p>To nasza pierwsza przygoda z AngularJS! </p> <p>Przywitajmy się:</p> <p>{{powitanie}}</p> </div> </body> </html> Umieszczamy skrypt angulara na stronie Definiujemy kontroler o nazwie PierwszyKontroler Umieszczamy dyrektywę ng-app informującą angulara o miejscu rozpoczęcia jego pracy Wykonanie polecenia zawartego w nawiasach angulara
Co tu się wydarzyło? Angular automatycznie inicjuje się po zdarzeniu DOMContentLoaded lub . Od tego momentu angular szuka dyrektywy ng-app, która oznacza root aplikacji. Jeżeli angular ją znajdzie: Ładuje moduł związany z dyrektywą Tworzy wstrzykiwacz aplikacji („injector application”) Kompiluje DOM traktująć dyrektywy ng-app jako korzeń kompilacji. To pozwala, aby tylko część DOM traktować jako aplikację angulara.
WSTRzykiwanie zależności (DEPENDENCY INJECTION) function PierwszyKontroler($scope){ $scope.powitanie = 'Hello AngularJS'; } Wstrzykiwanie zależności wykonujemy poprzez dodanie jej jako parametr funkcji kontrolera. Zależności rozpoznawane są po nazwie! Uwaga: W przypadku późniejszej minimalizacji plików i zmiany nazw parametrów wstrzyknięcia nie zadziałają w powyższej formie. Musimy zdefiniować dla angularowego injectora nazwy wstrzykiwanych zależności. PierwszyKontroler['$inject'] = ['$scope’]; Jest jeszcze druga możliwość – o niej później.
Data binding Two way data binding - wszelkie zmiany w widoku są natychmiast odzwierciedlane w modelu(kontrolerze), a wszelkie zmiany w modelu(kontrolerze) są propagowane do widoku. To sprawia, że widok jest graficzną projekcją modelu(danych w kontrolerze).
<html> <head> <script src="../angular-1.2.0.min.js"></script> <script> function DataBindingKontroler($scope){ $scope.imie; } </script> </head> <body ng-app> <div ng-controller="DataBindingKontroler"> <p>Data-binding </p> <p></p> <input ng-model="imie"></input> <p>Pierwszy sposób:</p> <span ng-bind="imie"></span> <p>Drugi sposób:</p> {{imie}} </div> </body> </html>
Kolejne przykłady… ng-repeat, WALIDACJA i Filtry
Moduł var app = angular.module('Routing',[]); app.config(function($routeProvider){ $routeProvider.when('/part1', {templateUrl:'./partial1.html',controller:'partial1Controller'}) .when('/part2/:id', {templateUrl:'./partial2.html',controller:'partial2Controller'}) .when('/part3', {templateUrl:'./partial3.html',controller:'partial3Controller'}) .otherwise({redirectTo:'/part1'}); }); Tworzymy modul angulara. Jego nazwę umieszczamy w dyrektywie ng-app. Konfigurujemy nasz moduł przy pomocy routeProvider-a, który umożliwia nam tworzenie podstron w naszej aplikacji. Angular JS posiada funkcjonalność parsowania adresu podanego w przeglądarce i na podstawie niego wyświetla odpowiednią treść.
ROUTING …/nazwaNaszejAplikacji#/part1
HTML na dopalaczach – dyrektywy ng-app ng-show ng-if ng-repeat ng-view ng-model …
Własne dyrektywy Tworzenie własnej dyrektywy polega na zdefiniowaniu obiektu dyrektywy i przekazaniu jej modułowi aplikacji: var myModule = angular.module(...); myModule.directive('directiveName', function (injectables) { var directiveDefinitionObject = {…} }; return directiveDefinitionObject; });
Obiekt dyrektywy - parametry restrict – definiuje typ dyrektywy E – element (tak jak np. span) A – atrybut (tak jak np. class) C – klasa (nazwa klasy) M – komentarz priority – ustala priorytet dyrektywy w przypadku kilku dyrektyw przy jednym elemencie terminal – jeżeli ustawiony na true to obecny priorytet dyrektywy będzie ostatnim jaki zostanie wykonany(dyrektywy z mniejszym priorytetem nie zostaną uruchomione) template – zamienia obecny element na zdefiniowany w tym parametrze kod html. Wszystkie atrybuty i klasy zostają skopiowane do nowego elementu. templateUrl – to samo co template tylko zawartość html jest pobierana z podanego adresu. replace – jeżeli ustawiony na true to template labo templateUrl nadpisuje, a nie dopisuje zawartość.
Obiekt dyrektywy – parametry cd. scope – parametr ten opisuje w jaki sposób dyrektywa będzie defniowała scope: false – nie tworzy nowego scope tylko dzieli scope z rodzicem true – tworzy nowy scope „dziedzicząc” po rodzicu. Tworzony z prototypu rodzica. {} – definiuje odizolowany scope, do którego możemy przekazywać dane za pomocą atrybutów elementu 3 rodzaje tych parametrów: @ - wartość przekazana jako string = - łączy (two way binding) zmienne w odizolowanym scope-ie i rodzicem & - łączy metodę z rodzica, którą odizolowany scope może wykonać controller – tworzymy kontroler dla dyrektywy. Metody i właściwości mogą być dostępne przez wstrzyknięcie do innej dyrektywy za pomocą parametru reqiure require – umożliwia przekazaniu kontrolera zdefiniowanej w parametrze dyrektywy. Nazwe dyrektywy możemy poprzedzić ? – nie wywoluje błędu, umożliwia opcjonalne wstrzyknięcie albo ^ - szuka kontrolera w rodzicach elementu
Obiekt dyrektywy – parametry cd. compile – funkcja umożliwiająca manipulacje DOM. Wykonywana tylko raz przy kompilacji np. compile function(tElement, tAttrs) { tElement.append('Added during compilation phase!'); } link – funkcja łącząca DOM ze scope(two way binding). Wykonywana za każdym razem przy zmianie modelu. np. link: function(scope, element, attrs) { if (element.hasClass('btn')) { element.addClass('btn-primary'); Czas najwyższy na przykłady..
Pytania i ZADANIA Napisać filtr do odwracania tekstu Napisać dyrektywę podmieniającą element <my-widget> na tekst Hello ANGULAR Napisać dyrektywę podmieniającą element z atrybutem my-widget na tekst ustawiony jako wartość tego atrybutu Napisać Dyrektywę powielającą zawartość elementu nrepeats tyle razy ile wsKaZuje atrybut tego elementu
Seam + RESTEASY – jak to zrobić? Dodać biblioteki do projektu Dodać spis dodanych biblioteki do pliku deployed-jars-ear.list EWENTUALNIE DODAĆ do pliku web.xml odpowiednie wpisy – definiowanie wzorca url dla naszych zapytań restowych Utworzyć obiekt z odpowiednią adotacją Utworzyć w obiekcie metodę odpowiadającą na zapytanie restowe Cieszyć się z API restowego w naszej aplikacji
Opis klasy jako usługi REST Klasa, która będzie wystawiać usługę typu REST powinna posiadać adnotację @javax.ws.rs.Path ze wskazaniem ścieżki pod jaką będzie widoczna usługa. Dodatkowo wskazujemy metodę, która będzie się wykonywać w momencie wywołania. Do tego celu wykorzystujemy adnotacje:@GET (lub @POST, @HEAD, @PUT, itd.) z pakietu javax.ws.rs. Dzięki temu możemy określić różne metody dla różnych typów wywołań (GET/POST/PUT/HEAD/...) REST'a. @javax.ws.rs.Produces z określeniem w jakim formacie będzie prezentowany wynik. Do dyspozycji mamy dwa popularne formaty: json ("application/json") i xml ("text/xml").
JSON – javascript object notation JSON - lekki format wymiany danych komputerowych. JSON jest formatem tekstowym, będącym podzbiorem języka JavaScript. Typ MIME dla formatu JSON to application/json. { „nazwa”:”Jakas nazwa”, „wartosc”:150, „lista”:[{„1”,”2”,”3”}]. „obiekt”:{„nazwa”:”nazwa1”,”kod”:15} }
JSON i XML {"menu": { "id": "file", "value": "File", "popup": { "menuitem": [ {"value": "New", "onclick": "CreateNewDoc()"}, {"value": "Open", "onclick": "OpenDoc()"}, {"value": "Close", "onclick": "CloseDoc()"} ] } }} <menu id="file" value="File"> <popup> <menuitem value="New" onclick="CreateNewDoc()" /> <menuitem value="Open" onclick="OpenDoc()" /> <menuitem value="Close" onclick="CloseDoc()" /> </popup> </menu>
Przykład klasy odpowiadającej na zapytanie restowe @Path("configResource") @Name("configResource") public class ConfigResource extends SecurityInvoiceResource { @In(create = true) ConfigResourceAction configResourceAction; @GET @Path("/config/{invoiceId}") @Produces({ MediaType.APPLICATION_JSON }) public Response getEditorConfiguration(@PathParam("invoiceId") final long invoiceId) { if (correctStatus(getInitStatus()) && correctRole(invoiceId)) { return buildResponse(configResourceAction.getConfiguration(invoiceId)); } return buildResponse(getInitStatus()); Adres do odwołania się do usługi: ../configResource/config/123
Jak to teraz połączyć z angularjs Zapisz() Pobierz()
Service & Factory Tych elementów angulara używamy zazwyczaj do definiowania modelu(danych) w MVC czyli jak i skąd mamy pobierać dane dla naszej aplikacji. Serwisy i fabryki używane są do wymiany danych między kontrolerami dzięki bardzo prostemu mechanizmowi wstrzykiwania zależności.
function HelloCtrl($scope, testService, testFactory) { $scope.fromService = testService.sayHello("World"); $scope.fromFactory = testFactory.sayHello("World"); } function GoodbyeCtrl($scope, testService, testFactory) $scope.fromService = testService.sayGoodbye("World"); $scope.fromFactory = testFactory.sayGoodbye("World"); app.factory('testFactory', function(){ return { sayHello: function(text){ return "Factory says \"Hello " + text + "\""; }, sayGoodbye: function(text){ return "Factory says \"Goodbye " + text + "\""; } }); app.service('testService', function(){ this.sayHello= function(text){ return "Service says \"Hello " + text + "\""; }; this.sayGoodbye = function(text){ return "Service says \"Goodbye " + text + "\""; Różnica polega na tym, że serwis zwraca funkcję z parametru, a fabryka obiekt zwracany przez funkcję z parametru.
Wykorzystanie $http i $resource app.factory('ConfigService', function($resource) { return $resource('/seam/resource/rest/configResource/config/:invoiceHeaderId', {invoiceHeaderId:'@invoiceHeaderId'}); }); { 'get': {method:'GET'}, 'save': {method:'POST'}, 'query': {method:'GET', isArray:true}, 'remove': {method:'DELETE'}, 'delete': {method:'DELETE'} }; Dodatkowe metody obiektu zwracanego przez $resource $scope.config = ConfigService.get({invoiceHeaderId:$routeParams.id}, function(){console.log(„Udane pobranie”)}, function(data){console.log(„Błąd”)});
AngularJS JBOSS + RESTEASY HTTP View Factory Rest RestAction Controler Seam business
AppJS AngularJS JBOSS + RESTEASY HTTP View Factory Rest RestAction Controler Seam business
Struktura Dużego projektu Angularjs root-app-folder index.html scripts controllers main.js ... directives myDirective.js filters myFilter.js services myService.js libs angular.js angular.min.js app.js styles views main.html
Przydatne linki, książki i narzędzia Strona domowa: http://angularjs.org Przydatne linki: https://egghead.io/lessons - zbiór video tutoriali https://leanpub.com/recipes-with-angular-js/read#leanpub-auto-introduction – zbiór przykładów zastosować AngularJS Książki – „AngularJS” (O’REILLY) i pdf „AngularJS In 60 Minutes” dodane do źródeł Narzędzia: AngularJS Baratang – do debugowania aplikacji Narzędzia do testowania - Jasmine