Archiwum autora: Marcin Kowalczyk

Dodawanie godzin w JavaScript

W naszej aplikacji możemy wpisywać tematy oraz imię i nazwisko prelegenta. Jednak tak naprawdę nic więcej się nie dzieje poza przepisaniem tych danych i dodaniem odpowiednich cudzysłowów i myślników. Dodajmy obliczanie godzin występów!

Chcemy do godziny rozpoczęcia wystąpienia np. 16:50 dodać jego czas trwania np. 15 minut, zapisane w formacie 00:15. Powinniśmy otrzymać godzinę zakończenia danego wystąpienia tj. 17:15. Dzięki takiemu formatowi, będziemy mogli wpisywać wystąpienia trwające dłużej niż godzinę np. półtorej godziny będzie zapisane 01:30.

W JavaScript niestety nie ma gotowej funkcji pozwalającej na sprasowanie godziny w takim formacie, ani ich dodawanie. Niemożliwe jest też dodanie własnego formatu (jak to można zrobić np. w Javie za pomocą DateTimeFormatter).

Własna funkcja dodająca godziny

Napiszmy więc własną funkcję. Chcemy przyjąć dwa parametry addTime(start, time):

  • start np. "16:50",
  • czas do dodania np. "00:15".

Wynikiem wywołania funkcji addTime("16:50", "00:15") powinien być tekst: "17:05".

Jak zaimplementować tę funkcję? Stwórzmy nowy obiekt new Date() i przypiszmy go do jakiejś zmiennej np. o nazwie now. Ustawmy godziny i minuty z pierwszego parametru za pomocą setHourssetMinutes. Następnie pobierzmy liczbę godzin i minut z drugiego parametru i dodajmy je do naszego obiektu (osobno godziny, osobno minuty).

Przykładowo jeśli liczbą minut z pierwszego parametru będzie 50, a będziemy chcieli dodać 25, to sumą będzie 75. Co się stanie jak ustawimy to jako minuty?

Tu JavaScript zachowa się ładnie i dostaniemy dokładnie to co chcieliśmy (licznik w godzinie się „przekręci”, wskoczy następna godzina i dostaniemy prawidłową liczbę minut; jest to niejakie dzielenie modulo 60).

Jak pobrać godziny i minuty z formatu HH:mm?

Jak już wspomniałem, nie ma w JavaScript możliwości dodania własnych formaterów. Po prostu pobierzmy odpowiednie liczby z ciągu tekstowego np. za pomocą metody split.

Metoda split(separator) działa w ten sposób, że zwraca tablicę z fragmentami tekstu podzielonymi za pomocą separatora. U nas separatorem będzie dwukropek „:”.

O to nam chodziło.

Kod funkcji będzie wyglądał tak:

Niby działa:

Ale w przypadku innych danych brakuje zer wiodących:

Zera wiodące

Zauważmy, że jeśli pobierzemy godzinę, minuty lub sekundy, które są poniżej 10, to otrzymamy liczbę bez zer wiodących:

Wynik:

Nie znalazłem eleganckiego rozwiązania. Trzeba po prostu zrobić if-a, który będzie to sprawdzał i doklejał „0” w odpowiednim miejscu:

Krócej można to zapisać:

Wynikiem będzie tekst:

Nasza poprawna funkcja będzie teraz wyglądać tak:

Jak widzimy, teraz wszystko działa poprawnie:

Wykorzystanie funkcji w AgendaEditor

Mamy gotową funkcję obliczającą godziny. Dodajmy ją do projektu.

Zmiany w HTML

Naszym widokiem z agendą obecnie jest plik home.html. Przede wszystkim musimy dodać tam pola gdzie będziemy mogli wpisać dane. Dodanie kolumny z miejscem na czas wystąpienia („time”):

Jak widzimy, system gridowy możemy stosować również do kolumn tabel, tak jak do całej strony.

Jako nowy wiersz wstawiamy dodatkowe pole analogiczne do innych:

Zostało nam do dodania pole, w które będziemy wpisywać godzinę startu całego wydarzenia. Dodajmy je nad tabelą:

Skorzystaliśmy z klasy form-group, w elemencie nią oznaczoną możemy umieścić napis label. Ustawiamy mu szerokość taką samą jak dla kolumny wyżej „Time” tzn. col-sm-2. Dodajmy również offset, który umieści pole nad kolumną tabeli „Time”. Po lewej stronie są kolumny „Title” (5), „Name” (2), „Surname” (2), co razem daje 5+2+2=9. Dlatego offset jest równy: col-sm-offset-9. Do tego nasze pole (2) i jeszcze puste miejsce, pod którym jest przycisk do usuwania (1), razem daje 12 bootstrapowych kolumn.

Zmiany w JavaScript

Przejdźmy teraz do naszego Angularowego kontrolera home.js.

Dodajmy naszą funkcję. W kodzie poniżej widzimy, że musimy ją wstawić dokładnie w kontrolerze. Nie będziemy jej przypisywać do $scope, bo nie ma takiej potrzeby (będzie wykorzystywana tylko lokalnie w kontrolerze):

W naszej liście $scope.list na początku umieszczamy jeden element za pomocą push. Pamiętajmy aby dodać tam nowe pole time: "", tak jak w kodzie wyżej.

Zajmijmy się teraz funkcją $scope.myResult, w której powinny wystąpić wywołania funkcji addTime, aby obliczyć godziny wystąpień.

Poprzednia wersja wyglądała tak:

Dodajmy sobie zmienną lastTime przechowującą godzinę zakończenia poprzedniego wystąpienia. Będzie to automatycznie początek kolejnego wystąpienia. Na początku oczywiście musimy ustawić ją jako czas startowy całego wydarzenia:

W pętli będziemy obliczać koniec wystąpienia za pomocą naszej funkcji addTime:

Oczywiście obliczone godziny musimy dopisywać do wykonu końcowego.

Oprócz tego dodajmy kilka warunków:

  • Nie wykonuj pętli (czyli nie rób niczego z naszą listą), jeśli nie została wpisana godzina wystąpienia:
  • Nie przetwarzaj danego wiersza jeśli nie został wpisany tytuł lub jeśli nie został wpisany czas wystąpienia (czasem zdarza się pusty string a czasem undefined).

Cały kod funkcji myResult będzie teraz wyglądał tak:

Podgląd działającej aplikacji

W zakładce „Code” oczywiście można podejrzeć kod całej aplikacji. Klikając tutaj, otworzymy ją w nowej karcie.

Obsługa dat i godzin w JavaScript

W JavaScript wszystko związane z datą i godzinami praktycznie zamyka się w jednej klasie Date. Jej dokumentację możemy przeczytać na Mozilla Developer Network: Date. Obsługa czasu w JavaScript jest dosyć uboga, w szczególności w porównaniu do innych języków programowani np. w Javie, w której mamy multum przeróżnych klas do obsługi dat, godzin, stref czasowych, parserów, kalendarzy itd.

Trochę historii

Klasa Date w JavaScripcie powstała na wzór tej w Javie 1.0 java.util.Date. Historyczną dokumentację JDK 1.0.2. klasy Date z 1996 roku możemy znaleźć np. w Internet Archive WaybackMachine (oczywiście jeszcze na stronie Sun, przed przejęciem przez Oracle). Jak widzimy konstruktory i metody są niemal identyczne. W Javie przez lata biblioteki bardzo się rozwinęły, a w JavaScripcie jakby się czas zatrzymał. Przez to pozostały niewygodne w użyciu konstrukcje, ale musimy sobie z tym poradzić.

Źródło: http://www.wykop.pl/wpis/16780451/programowanie-javascript-heheszki-humorinformatyko/

Źródło: http://www.wykop.pl/wpis/16780451/programowanie-javascript-heheszki-humorinformatyko/

Jak widzimy na grafice powyżej, w JavaScript jest metoda getYear(), która, możemy się domyślać, zwraca rok. Dlaczego więc zwróciła liczbę 116? Jak możemy przeczytać w dokumentacji, getYear() zwraca rok minus 1990. Dla lat przed 2000 mogło być to wygodne (np. dla roku 1996 zwracało 96). Jednak w tym przypadku: 2016-1900=116. Na szczęście ta metoda została oznaczona jako przestarzała. Zamiast niej jest getFullYear() zwracająca pełny rok.

API dat w JavaScript

Dostępne są cztery konstruktory klasy Date:

  • Pusty, dzięki któremu ustawiony zostanie aktualny czas:
  • Z parametrem przyjmującym czas w formacie uniksowym w milisekundach (liczba milisekund od 1 stycznia 1970 roku). Przykładowo:
  • Podawane wartości dla każdej jednostki czasu (rok i opcjonalnie miesiąc, dzień, godzina, minuty, sekundy, milisekundy):

    Trzeba pamiętać, że w JavaScript miesiąc jest reprezentowany przez liczby od 0 do 11. Przykładowo:
  • Tekst (string) zawierający datę w odpowiednim formacie np. ISO 8601 tj. YYYY-MM-DDTHH:mm:ss.sssZ. Przykładowo:

I cały zestaw getterów i setterów. Możemy pobrać np. godzinę z daty getHours() lub ustawić minuty setMinutes(liczbaMinut). Ogólnie wygląda to tak: get lub set i nazwa jednostki czasowej np. Miliseconds, Seconds, Minutes, Hours, FullYear (a nie samo Year jak wyżej opisywane). W tabeli poniżej przedstawiono zestawienie.

get set
milisekundy getMiliseconds() setMiliseconds(liczbaMilisekund)
sekundy getSeconds() setSeconds(liczbaSekund)
minuty getMinutes() setMinutes(liczbaMinut)
godziny getHours() setHours(liczbaGodzin)
dzień tygodnia (0-6) getDay()
dzień miesiąca (1-31) getDate() setDate()
miesiąc (0-11) getMonth() setMonth()
rok getFullYear() setFullYear(rok)

Jest jeszcze kilka dodatkowych metod, które możemy sprawdzić w dokumentacji np. getTime() zwracający czas uniksowy w milisekundach.

Dzięki wyżej wymienionym metodom możemy modyfikować wcześniej stworzony obiekt z datą. Przykład:

Do interaktywnej zabawy z JavaScript można użyć np. konsoli przeglądarki (F12 w Chrome, zakładka „Console”):

Konsola Chrome godziny

Konsola Chrome

Zewnętrzne biblioteki

I to na tyle z pomocy samego JavaScriptu z obsługą dat i godzin. O resztę musimy zadbać sami. Istnieją zewnętrzne biblioteki usprawniające pracę np.

Jednak do prostej czynności (np. dodanie dwóch godzin do siebie) nie chcemy używać zewnętrznej biblioteki (bo zawsze to dodatkowe utrzymanie kodu, aktualizacje np. bezpieczeństwa, dodatkowe obciążenie – nawet jak biblioteka jest mała, to jednak dodatkowe połączenie do serwera; chyba żeby konkatenować pliki JavaScriptowe).

Ale do bardziej zaawansowanych zadań z czasem lub po prostu większej ich liczby polecam użyć którejś biblioteki.

Uruchamianie aplikacji AngularJS

Tworzymy stronę internetową w pliku index.html i otwieramy ją w przeglądarce, aby podejrzeć wprowadzone zmiany. Tak samo postępowaliśmy z AngularJS. O co więc tutaj chodzi?

Błąd: Cross origin requests…

W poprzednim wpisie dodaliśmy routing do aplikacji w AngularJS. Jeśli teraz po prostu otworzymy index.html, to przełączanie pomiędzy zakładkami w niektórych przeglądarkach nie będzie działać. Możemy sprawdzić w konsoli (np. F12 w Chrome) jaki błąd został wygenerowany:

XMLHttpRequest cannot load file:///C:/git/agenda-editor/home/home.html. Cross origin requests are only supported for protocol schemes: http, data, chrome, chrome-extension, https, chrome-extension-resource.

Dotyczy on zabezpieczeń przeglądarki (koncepcja same origin policy). Kiedyś poprzez AJAX czyli obiekt XMLHttpRequest (w skrócie: XHR) nie można było się odwoływać do zasobów spoza domeny, na której umieszczony była aplikacja (były różne obejścia tego problemu). Obecnie jest to możliwe dzięki Cross-Origin Resource Sharing (w skrócie CORS). Jednak trochę inaczej działa to w różnych przeglądarkach i np. w Firefoxie takiego błędu nie dostaniemy, a w Chrome już tak. W nim jest to możliwe tylko dla protokołów wymienionych w błędzie (np. HTTP), jednak już nie dla plików lokalnych: file://.

Można to obejść, uruchamiając Chrome z parametrem --allow-file-access-from-files (czy nawet --disable-web-security). Czyli np.:

"C:\Program Files (x86)\Google\Chrome\Application\chrome.exe" --allow-file-access-from-files

Jednak nie jest to zalecane, a może nawet być niebezpieczne. Omijanie zabezpieczeń przeglądarki nie wydaje się dobrym pomysłem. Zróbmy to tak, jak powinno być.

Uruchomienie na serwerze

Nasza aplikacja docelowo ma być umieszczona na jakimś serwerze. Jeśli ją gdzieś wrzucimy, zauważymy, że problem nie występuje (bo pliki idą po HTTP). Postawmy więc lokalny serwer do pracy.

Popularne rozwiązanie: serwer Apache HTTP Server

Osoby tworzące strony internetowe w PHP na pewno znają Apache HTTP Server (bo kod aplikacji w PHP przed uruchomieniem musi być zinterpretowany). Jest darmowy, można go zainstalować na Linuxie, Windowsie itd. W internecie dostępnych jest wiele materiałów i tutoriali. Po instalacji po prostu wrzucamy pliki naszej aplikacji do odpowiedniego folderu serwera i uruchamiamy.

Można też użyć lekkiej, szybkiej w instalacji i konfiguracji wersji WAMP Server.

Szybkie rozwiązanie: http-server

Jeszcze szybszym i wygodniejszym rozwiązaniem jest skorzystanie z http-server. Jednak, aby go zainstalować musimy mieć menadżer pakietów JavaScript npm dla Node.js.

Dlatego zainstalujmy najpierw Node.js (npm jest już wbudowany): https://nodejs.org/en/

Teraz w wierszu poleceń możemy uruchomić instalację http-server (przełącznik -g oznacza instalację globalną tzn. będzie dostępna wszędzie w wierszu poleceń):

npm install http-server -g

Uruchamianie aplikacji w http-server

Sposób 1

Teraz uruchomić wiersz poleceń i przejść do folderu z naszą aplikacją (np. za pomocą polecenia cd). W Windowsie szybko możemy to zrobić przytrzymując klawisz SHIFT, klikając prawym klawiszem myszy w folderze z aplikację i wybrać pozycję „Otwórz okno polecenia tutaj”.

Wpisujemy polecenie:

http-server

Mamy uruchomiony serwer, na którym jest udostępniana aktualna zawartość folderu, z którego uruchomiliśmy serwer. Wystarczy wejść po adres: http://localhost:8080/ i możemy oglądać naszą działającą aplikację.

Sposób 2

Alternatywnie, możemy uruchomić wiersz poleceń i wpisać:

http-server ścieżka_do_folderu_z_aplikacją

I tak samo jak poprzednio, aplikacja jest dostępna pod localhost:8080.

Serwer wbudowany w IDE

Jak będziemy już tworzyli aplikację w Springu (Java EE), to i tak będziemy musieli uruchamiać ją na serwerze np. Apache Tomcat. Integruje się go ze środowiskiem programistycznym IDE (np. Eclipse, IntelliJ IDEA). Wtedy już nie będzie problemu z wrzucaniem na serwer aplikacji w Angularze.

Zanim będziemy budować aplikację w Springu, możemy skorzystać np. z IDE WebStorm. Tam też jest wbudowany serwer, dzięki któremu możemy uruchomić naszą aplikację w AngularJS.

Menu w AngularJS czyli routing

Menu, zakładki na stronie internetowej, linki do podstron. To coś jest tak naturalne, że nie wyobrażamy sobie budowania bez tego aplikacji internetowych.

W HTML robi się to bardzo prosto. Po prostu wstawimy linki <a> do kolejnych plików podstrona1.html, podstrona2.html itd. Ma to jednak wady. Musimy kopiować całą zawartość strony (menu, stopka itd.), aby zmienić tylko jej środek (zawartość na którą chcemy się przełączyć). Jeśli zmienimy np. coś w menu, musimy ręcznie zaktualizować to na wszystkich podstronach. Dodatkowo musimy dbać np. o podświetlenie pozycji w menu w zależności od tego, na której zakładce jesteśmy.

W różnych językach programowania (np. PHP) możemy to zautomatyzować. We frameworkach do budowy aplikacji internetowych jest to różnie rozwiązane. Oczywiście w AngularJS również jest na to sposób i nazywa się routing. Na początku wygląda to trochę skomplikowanie, ale w późniejszej pracy jest bardzo wygodne. Dzięki temu można budować nawet proste strony z wykorzystaniem możliwości Angulara.

W Angularze dodatkową zaletą jest to, że podczas przełączania zakładek, nie będzie przeładowywana cała strona, a tylko odpowiedni jej fragment. Jest to typ aplikacji SPA (Single Page Application).

Integracja z Bootstrapem w AgendaEditor

Na końcu poprzedniego wpisu uzyskaliśmy już całkiem ładną aplikację dzięki podłączeniu Bootstrapa. Jak widzicie dodałem w Bootstrapie menu na górze, jednak jest ono nieaktywne. Zróbmy z niego użytek.

W aplikacji AgendaEditror chciałbym na początek takie zakładki:

  • Home (zakładka z agendą i polami do wpisywania),
  • Import (potem zaimplementujemy funkcjonalność, dzięki której będzie można w pole wklejać dane do agendy),
  • About (informacje o aplikacji, kontakt itd.).

Routing w AngularJS i struktura aplikacji

Od wersji 1.2 w Angularze routing jest wydzielony do osobnego modułu ngRoute w pliku angular-routing.js, który możemy znaleźć na stronie projektu. Musimy go dołączyć do naszej aplikacji, jednak pamiętając o zachowaniu kolejności dodawania, która była już omówiona we wpisie, do którego linkuję.

Bez tego, po skonfigurowaniu routingu, otrzymalibyśmy błąd:

Error: $injector:modulerr
Module Error

Oczywiście należy w aplikacji dodany moduł zaincludować:

Kolejną rzeczą, którą musimy zrobić, to dodanie jakiegoś elementu (zazwyczaj <div>) z dyrektywą ng-view w pliku index.html. Angular w tym miejscu będzie podmieniał zawartość kolejnych podstron.

Routing w Angularze działa w ten sposób, że podmienia element z dyrektywą ng-view na plik szablonu (template), na podstawie adresu wpisanego w przeglądarce np. http://nazwaAplikacji/#/home.

Potrzebujemy do każdej podstrony:

  • plik z szablonem (html),
  • plik z kontrolerem (js).

Należy skonfigurować $routeProvider, w którym określimy jaki adres będzie odpowiadał jakiemu szablonowi i kontrolerowi.

Jak podzielić naszą aplikację na pliki? Jaka powinna być struktura projektu? Są dwa sposoby.

Sposób 1 – pogrupowane js i html

Tak jak już dawno robiło się w projektach: trzymajmy razem pliki js w jednym folderze, a pliki html w innym folderze:

  • index.html
  • css/
    • style.css
  • js/
    • app.js
    • HomeController.js
    • ImportController.js
    • AboutController.js
  • pages/
    • home.html
    • import.html
    • about.html

Każdemu kontrolerowi (np. HomeController.js) odpowiada jeden plik szablonu (np. home.html).

Możemy teraz dołączyć pliki kontrolerów do naszego index.html:

W każdym pliku umieszczamy kontroler według wzoru tak jak wcześniej (tu np. ImportController.js):

A w szablonach umieszczamy treść, która ma być podmieniana:

Prawda, że wygląda to dobrze?

A teraz najważniejsza część: konfiguracja $routeProvider (w pliku app.js):

Po prostu na obiekcie naszej aplikacji wykonujemy metodę config, która przyjmuje parametr z funkcją, w której jest konfiguracja. W konfiguracja dla każdej podstrony określamy:

  • when – czyli jaki ciąg znaków będzie w adresie aplikacji po znaku hash np. /#/home.
  • templateUrl – gdzie jest plik z szablonem, który ma być wstawiony na stronę w miejsce ng-view.
  • controller – jak nazywa się kontroler, który ma obsługiwać daną podstronę (będzie dynamicznie podmieniany). Jest to pole opcjonalne (nie na każdej podstronie potrzebujemy kontrolera).

Na koniec możemy dodać jeszcze otherwise (i reszta konfiguracji jak w przypadku when), który określa co ma się stać (na którą podstronę wejść) w przypadku jak nie można było dopasować do żadnej reguły wymienionej we when.

Cały kod wraz ze strukturą możecie podejrzeć na Githubie: https://github.com/mkczyk/agenda-editor/tree/routing-grouped-types-angularjs

Podgląd działającej aplikacji sposobem 1:

Sposób 2 – osobny folder dla każdej podstrony

Drugi sposób na początku trudniej zrozumieć (bo konfiguracja $routeProvider jest porozrzucana po wielu plikach), ale potem dużo łatwiej z nim pracować. Każda podstrona na swój folder, w którym znajduje się plik szablonu i kontrolera. W kontrolerze jest umieszczona konfiguracja $routeProvider.

Jeśli w przyszłości będziemy chcieli dodać kolejną podstronę, to wystarczy skopiować jeden folder, przerobić pliki (z konfiguracją), dodać w index.html pozycję w menu i już mamy gotowe.

  • index.html
  • app.js
  • css/
    • style.css
  • home/
    • home.html
    • home.js
  • import/
    • import.html
    • import.js
  • about/
    • about.html
    • about.js

Dołączmy pliki do naszego index.html:

W głównym pliku konfiguracyjnym app.js możemy umieścić tylko to co nie pasuje do żadnej podstrony czyli otherwise:

Szablony HTML będą wyglądały identycznie jak w poprzednim sposobie. A cała potęga tego sposobu tkwi w konfiguracji danej podstrony (tu import.js):

W środku konfiguracja wygląda tak samo jak w poprzednim sposobie. Tylko, że tu dotyczy jedynie danej podstrony.

Dodatkowa uwaga: jeśli kontroler nam się mocno rozrośnie, możemy konfigurację podzielić na dwa pliki (plik z kontrolerem i plik z konfiguracją $routeProvider). Tylko trzeba pamiętać, żeby w index.html dodawać po dwa pliki.

Cały kod  tego sposobu wraz ze strukturą możecie podejrzeć na Githubie: https://github.com/mkczyk/agenda-editor/tree/routing-grouped-subpages-angularjs

Podgląd działającej aplikacji sposobem 2:

Korzystanie z Bootstrapa

W poprzedniej części poznaliśmy jak podłączyć Bootstrapa do aplikacji AngularJS. W tym zobaczymy jak wykorzystać jego możliwości i zmienić wygląd naszej aplikacji.

Oczywiście strony internetowe napisane z wykorzystaniem samego Bootstrapa będą wyglądać podobnie jak inne. Dlatego nie zaleca się pozostawienia jej końcowo w takiej formie, szczególnie jeśli ma być dla klienta i użytkowników końcowych. Należałoby wtedy chociaż zastosować jakiś unikalny, ładny szablon (niektórzy uważają, że Bootstrap nadaje się tylko do prototypowania, a końcowa wersja jednak powinna być specjalnie napisanym szablonem). Jednak dla naszego zastosowania, Bootstrap w zupełności wystarczy, aby nadać trochę lepszy niż surowy wygląd. W końcu to aplikacja narzędziowa, a nie strona wizytówka. Podobnie, wykorzystaniem Bootstrapa bardzo fajnie tworzy się przeróżne panele administracyjne.

Stosowanie klas CSS Bootstrapa

Jeśli mamy dołączone pliki Bootstrapa do naszej aplikacji, możemy przystąpić do działania.

Dokumentacja Bootstrapa jest naprawdę dobra. W zakładkach na górze znajdziemy link do CSS, czyli opis jakie klasy możemy zastosować i jak to będzie wyglądać.

Nasza aplikacja wyglądała tak:

Przed Bootstrapem

Po dodaniu Bootstrapa, nastąpił reset stylów dodanych domyślnie przez przeglądarkę:

Dodany Bootstrap

Pierwsze zastosowanie – przyciski

W naszym projekcie mamy przyciski <button>. W dokumentacji możemy sprawdzić przykłady jak dodać do nich klasy i z czego możemy wybierać. Mamy do wyboru różne klasy, różniące się kolorami: default, primary (domyślnie niebieski, zwykły przycisk), success (można wykorzystać np. dla zatwierdzania czegoś), info, warning (przyciski nad którymi użytkownik powinien się zastanowić zanim kliknie), danger (zazwyczaj usuwanie czegoś).

Oczywiście nie zapominajmy zachować funkcjonalności wcześniej stworzonej w naszej aplikacji:

Analogicznie postąpmy z przyciskiem do usuwania wiersza. Mamy do wyboru różne rozmiary przycisków: standardowy (bez dopisywania niczego), duży btn-lg, mały btn-sm, bardzo mały btn-xs.

Teraz przyciski w naszej aplikacji wyglądają już lepiej:

Bootstrap przyciski

Tak samo możemy postąpić z innymi elementami.

Pola tekstowe

Dodajmy klasę form-control do pól <input>, dzięki czemu będą ładniej się prezentować:

Inputy Bootstrap

Ogólnie, na przyszłość, formularze należy zamykać w tagach <form>. Więcej o nich w dokumentacji.

Komponenty

Oprócz stosowania stylów CSS, mamy możliwość dodawania komponentów z Bootstrapa. Na wyniki dodajmy panel, żeby były bardziej widoczne.

Co da efekt:

Panel Bootstrap

Siatka Bootstrapa (Grid system)

Tworzenie szablonów w Bootstrapie jest szybkie. Przyjęto system „siatkowy” (grid) do tworzenia responsywnych stron. To znaczy, że stronę można podzielić na maksymalnie 12 kolumn w każdym rzędzie. Kolumny na różnej wielkości ekranów (lub zmian rozmiarów okna) będą zachowywały się inaczej. Podczas zmniejszania okna, kolumny stają się węższe, a jeśli już się nie mieszczą, to przeskakują jedna pod drugą.

Rzędy (klasa row) umieszcza się w kontenerze (klasa container). Czyli tak naprawdę tam będzie znajdować się główna zawartość strony.

Jeśli chcemy podzielić stronę na dwie kolumny, musimy pogrupować je po 6 kolumn bootstrapowych (bo 12/2=6). Będzie to wyglądać w ten sposób:

Więcej o gridach można poczytać w dokumentacji lub sprawdzić kod źródłowy i działanie oficjalnego przykładu.

W naszej aplikacji na dużych (szerokich) ekranach będą widoczne dwie kolumny:

Grid 6 duży

Jednak na mniejszych (węższych) ekranach lub po zmniejszeniu okna, jedna kolumna przeskoczy na dół:
Grid 6 mały

Menu

Dodajmy menu do naszej aplikacji. Na razie jeszcze nie będzie wykorzystywane, ale już niedługo to się zmieni.

Możemy wykorzystać najprostszy szablon z oficjalnej strony, w którym umieszczono menu (wystarczy zajrzeć w źródło strony). Po drobnym dostosowaniu kodu do własnych potrzeb, może on przyjąć taką formę:

Więcej o nawigacji i jej różnych typach można, jak zawsze, przeczytać w dokumentacji.

Jest jednak jeszcze jeden haczyk. Po dodaniu manu, zasłonił on część naszej aplikacji. Należy dodać margines na naszej stronie o wysokości takiej, jakiej jest menu (50px, ale dodajmy przy okazji większy odstęp, czeli razem np. 70px).

Gdzie to dodać? Utwórzmy nowy plik style.css – w przyszłości pewnie jeszcze nieraz nam się przyda, będziemy w nim umieszczać nasze reguły stylów. Oczywiście musimy również załadować nasz plik w aplikacji (tzn. dołączyć go do index.html):

Nasza aplikacje wygląda tak:
Szablon BootstrapZauważmy, że jeśli zmniejszymy okno, to kolumna przechodzi na dół, a linki w menu znikają:
Szablon mały 1Oczywiście mamy do nich dostęp poprzez przycisk. Jeśli go klikniemy, pozycje menu pokazują w wysuwanym polu:

Szablon mały 2

Podsumowanie

To co wyszło w dzisiejszym wpisie, możecie podejrzeć tutaj na żywo:

Jak zawsze, udostępniam kod na GitHubie w repozytorium agenda-editor w  branchu bootstrap-angularjs:
https://github.com/mkczyk/agenda-editor/tree/bootstrap-angularjs

Podpięcie Bootstrapa do AngularJS

Jak szybko zrobić ładny interfejs graficzny aplikacji? Skorzystajmy z front-endowego frameworka Bootstrap. Wystarczy dodać plik z Bootstrapem, kilka klas i już mamy przyzwoity wygląd. W przyszłości z łatwością będziemy mogli rozbudowywać aplikację, a jednocześnie dbać o to, żeby wyglądała poprawnie.

Stroną domową Bootstrapa jest: http://getbootstrap.com/.

Istnieje książka pt. Bootstrap. Tworzenie interfejsów stron WWW. Technologia na start! (autor: Syed Fazle Rahman, oryginalny tytuł Jump Start Bootstrap). Jednak dokumentacja jest na tyle dobra, a Boostrap na początku na tyle prosty, że zazwyczaj nie ma potrzeby sięgania po dodatkowe źródła. Jeśli będziemy chcieli zgłębić dokładne działanie frameworku, to ta pozycja może się kiedyś przydać.

Dodanie Bootstrapa do aplikacji

W zakładce Getting Started na oficjalnej stronie jest opisane skąd ściągnąć Bootstrapa. Podobnie jak w przypadku Angulara, tu też możemy ściągnąć plik na dysk i dołączyć do projektu lub wykorzystać udostępniony link wykorzystujący zewnętrzne serwery. Dołączmy Bootstrapa w podobny sposób jak to robiliśmy z Angularem.

Obecnie najnowszą wersją Bootstrapa 3 jest 3.3.6. Możemy użyć pliku bootstrap.css lub co zalecane zminifikowanego bootstrap.min.css:

Jednak do działania niektórych funkcji Bootstrapa wymagany jest również plik JavaScript bootstrap.js (czyli zminifikowany bootstrap.min.js):

Jednak, aby on działał, prawidłowo potrzebne jest dołączenie biblioteki jQuery. Można ją znaleźć tutaj lub tutaj. Do wyboru mamy wersje 1.x lub 2.x. Wersja 2.x nie wspiera Internet Explorera 6, 7 i 8. A do działania Bootstrapa wystarczy nam wersja 1.x, dlatego ją wybierzmy (obecnie jest to wersja 1.12.3):

Kolejność dodawania

Musimy pamiętać o poprawnej kolejności dodawania plików zewnętrznych do projektu. Najpierw dodajmy te, które nie zależą od niczego, a potem te, które zależą od bibliotek wyżej. Czyli w naszym przypadku:

  1. Bootstrap CSS bootstrap.css
  2. jQuery jquery.js
  3. Bootstrap JS bootstrap.js
  4. AngularJS angular.js
  5. nasz kontroler AngularJS controller.js

W naszej aplikacji AgendaEditor będzie to wyglądało tak:

Później, gdy rozbudujemy projekt, kolejność ładowania plików będzie wyglądała następująco:

  1. Pliki CSS:
    1. Bootstrap bootstrap.css
    2. nasze style np. style.css
  2. Pliki JavaScript:
    1. jQuery jquery.js
    2. Bootstrap bootstrap.js
    3. AngularJS angular.js
    4. moduły AngularJS np. angular-route.js
    5. nasze kontrolery np. controller.js

Jeśli liczba plików zacznie nam się rozrastać, będziemy używać wielu bibliotek, warto zainteresować się frameworkiem RequireJS do zarządzania zależnościami, który ulepszy sposób ładowania plików. Na razie jednak pozostańmy przy najprostszym rozwiązaniu.

Sprawdzenie czy Bootstrap działa

Nasza aplikacja na razie wyglądała tak:

Przed Bootstrapem

Po dodaniu Bootstrapa, nastąpił reset stylów dodanych domyślnie przez przeglądarkę. Jeśli dodaliśmy poprawnie pliki, aplikacja powinna wyglądać w ten sposób:

Dodany Bootstrap

W kolejnej części przedstawię jak zastosować Bootstrapa do naszych elementów interfejsu graficznego.

AgendaEditor: dynamiczne dodawanie pól

Z poprzedniego wpisu mamy formularz, który jest połączony z listą z danymi. Dane są automatycznie przepisywane. Teraz chcielibyśmy, aby nie było ograniczenia co do wierszy. Zróbmy więc tak, żebyśmy mogli dodawać je dynamicznie, podczas działania aplikacji.

Dodawanie wiersza przyciskiem

Pod tabelą dodajmy przycisk:

Skorzystaliśmy z dyrektywy ng-click, której parametrem jest przypisana funkcja addItem() (działa to bardzo podobnie do zwykłej metody onclick w czystym JavaScript).

Przejdźmy zatem do definicji funkcji:

Nie ma tu nic zaskakującego (jeśli ktoś czytał poprzedni wpis). Po prostu na listę dodajemy kolejny obiekt (z wypełnionymi pustymi danymi). Dzięki temu pojawi się kolejny wiersz z polami do wpisywania. Mało pracy, a dobry efekt.

Usuwanie wiersza przyciskiem

Dodajmy kolejną kolumnę w tabeli (czyli komórkę <td> powtarzaną w wierszach <tr>), a w niej przycisk z teksem minus:

Tak samo korzystamy tu z dyrektywy ng-click. Jednak tym razem nie wywołujemy funkcji z kontrolera, tak jak to było w przypadku dodawania wiersza. Jeśli fragment kodu jest mały, możemy go od razu umieścić w tym samym miejscu. Z listy usuwamy ten element, w którym został kliknięty przycisk. Do usuwania z listy w JavaScript służy metoda splice. Pierwszym parametrem jest od którego elementu mają być usuwane, a drugim, ile elementów ma być usuniętych (w tym wypadku jeden). Aby otrzymać numer elementu, w którym jest przycisk, wystarczy skorzystać z $index (jest to dostępne dzięki temu, że ng-repeat tworzy swój własny, „lokalny” scope).

Automatyczne dodawanie wiersza, gdy jest ostatni

Dodajmy jeszcze jedną funkcjonalność, która poprawi komfort z korzystania z aplikacji. AngularJS sam do tego zachęca, gdyż często dobre efekty można uzyskać stosunkowo małym kosztem.

Niech nowy wiersz dodaje się automatycznie, gdy klikniemy ostatni (wtedy będzie wiadomo, że użytkownikowi zaczyna brakować miejsca).

W wierszu tabeli <tr> dodajmy kolejną dyrektywę (po za istniejącą już ng-repeat): ng-click="$last && addItem()". Po kliknięciu wiersza wykona się to co w niej jest umieszczone. Najpierw jest umieszczona właściwość $last (dostępna z lokalnego $scope). Przyjmuje wartość true, jeśli aktualnym (klikniętym) elementem jest ostatni. Wtedy wykonuje się również to co jest po operatorze and oznaczonym podwójnym ampersandem czyli funkcja addItem() (ta sama co po kliknięciu przycisku Add).

Wynik

index.html

controlller.js

Wynik działania:

Kod na GitHub

Kod tej części aplikacji umieściłem na GitHubie w repozytorium agenda-editor w  branchu form-angularjs:
https://github.com/mkczyk/agenda-editor/tree/form-angularjs

 

AgendaEditor: lista i formularz w AngularJS

W tym wpisie pokażę jak zrobić prosty formularz w AngularJS, który będzie podpięty do listy z danymi. Wartości z pól tekstowych będą przepisywane automatycznie w miejsce wynikowe poprzez listę.

Weźmy szablon aplikacji z wpisu, w którym był omówiony kontroler. Będzie to nasz punkt wyjściowy do rozbudowy aplikacji.

index.html

controller.js

Szablon formularza w tabeli w HTML

Chcemy mieć gdzie wpisywać dane (tytuł, imię, nazwisko itd.). Najlepiej jak będą to pola tekstowe <input>, tak jak w poprzednim przykładzie. Tych pól będzie kilka dla jednego rekordu (jednego wystąpienia), a wierszy będzie kilka. Są przynajmniej dwa sposoby jak moglibyśmy zorganizować te pola:

  • lista nieuporządkowana <ul> z elementami <li>,
  • tabela <table> z wierszami <tr> i komórkami <td>.

Na pierwszy rzut oka wydaje się, że powinniśmy użyć listy (biorąc pod uwagę dobrych kilka lat walki z wypieraniem tabelek ze stron). Jednak mamy tu dane tabelaryczne i dlatego spróbujemy użyć tu tabeli (dzięki temu będziemy mieli też ładne nagłówki <th> w pierwszym wierszu <tr>).

W pierwszym pliku dodajmy tabelę:

Jak widzicie, dla pól <input> została zastosowana dyrektywa, która binduje model (tzn. odpowiednie „zmienne”). To co zostanie wstawione do modelu, będzie wyświetlone w polach tekstowych. I to co zostanie wpisane w pola tekstowe, automatycznie będzie dostępne w modelu.

Pojawiła się tu także nowa dyrektywa ng-repeat. Najczęściej używa się jej w ten sposób: ng-repeat="element in listaElementow". Działa ona w ten sposób, że powtarza element HTML, w którym jest umieszczona, tyle razy, ile jest elementów w liście (tak jakby pętla for each znana z innych języków – przechodzi po każdym elemencie). Każdy wybrany element jest dostępny w nazwanej przez nas zmiennej item. Przyjąłem, że lista zawierała obiekty, więc możemy odwołać się do pól obiektu. I tak, możemy z modelu wybrać np. tytuł poprzez item.title oraz zbindować go do pola tekstowego.

Dzięki temu zostanie wyświetlonych tyle linii w tabeli (z potrzebnymi polami), ile jest elementów na liście. Ale potrzebujemy właśnie tą listę i to dostępną w $scope.

Lista w kontrolerze w JavaScript

W kontrolerze deklarujemy listę (a właściwie tablicę):

Jeśli teraz odwołamy się do jakiegoś elementu lub pola, będzie miało wartość undefined. Aby pola tekstowe domyślnie zawierały puste wartości, a nie brzydką wartość nieokreśloną, musimy dodać obiekty i zainicjalizować pola. Nowy obiekt tworzymy za pomocą nawiasów klamrowych {} a w środku wpisujemy po przecinku nazwę pola, przecinek i wartość.  Wygląda to tak: {title: "", name: "", surname: "", time: ""}.

My chcemy od razu dodać kilka obiektów na naszą listę, aby domyślnie wyświetliło kilka wierszy do wpisywania. Użyjemy do tego metody push na liście. Czyli dodanie obiektu do listy w $scope powinno wyglądać tak: $scope.list.push(obiekt).

Możemy od razu dodać kilka obiektów w pętli:

Teraz powinny wyświetlić się nam trzy wiersze z polami.

Funkcja tworząca wynikowe dane

Oczywiście chcemy jeszcze, aby wpisywane dane do pól tekstowych były przepisywane zgodnie z naszymi wymaganiami. W tym celu  zmodyfikujemy funkcję myResult() z początkowego kodu.

Chcemy otrzymać listę wyników. Dlatego zadeklarujmy tablicę var result = []. Następnie w pętli, przechodźmy po wszystkich elementach naszej listy $scope.list. Łączmy dane z pól i wstawiajmy jako nowy element na listę wyników result.push(wynikWiersza). Na koniec zwróćmy listę wyników (bo przecież to jest funkcja). Kod wygląda tak:

W zmiennej concat po prostu znalazły się połączone (skonkatenowane) dane z pól (na razie godziny i czas wystąpienia zostały celowo pominięte – ich obsługa będzie w kolejnych wpisach).

Wyświetlenie listy wyników

Dodajmy po prostu element <div>, w którym przejdziemy po wszystkich elementach z listy, którą zwraca funkcja myResult(). Element <div> zostanie powtórzony tyle razy ile jest elementów na liście. Wyświetlmy w nim połączone dane i na koniec przejście do nowej linii.

Dlaczego nie robić nowych linii w funkcji?

Dlaczego nie mogłem połączyć wszystkich danych w funkcji, dodać znaki nowej linii i zapisać do jednej zmiennej całego tekstu? A potem tylko go wyświetlić? (Uniknęlibyśmy pracy z dodawaniem każdego wynikowego wiersza do listy, a potem wyświetlania ich w pętli)

Tzn. kod funkcji wyglądałby tak:

A w HTML wyświetlilibyśmy jedynie wynik funkcji:

Byłaby dużo prościej, prawa?

Ale nie działa. Znaczniki <br /> nie są zamieniane na nowe linie, tylko pokazują się jako zwykłe znaki. Jest to zabezpieczenie AngularJS przed umieszczaniem kodu HTML na stronie przez użytkownika.

Jeśli naprawdę chcemy, jak można to wyłączyć? We wcześniejszych wersjach Angulara istniała dyrektywa ng-bind-html-unsafe, która pozwalała zbindować zmienna, w której jest HTML i go wyświetlać. Wyglaładałoby to tak:

Obecnie ta dyrektywa została usunięta. Jak sobie z tym poradzić? Trzeba zrobić dwie rzeczy:

  • Zastosować do bindowania dyrektywę ng-bind-html, co wygląda tak:
  • Wstrzyknąć moduł ngSanitize. Aby to zrobić należy:
    • W inicjalizacji aplikacji dodać moduł:
    • Dodać plik angular-sanitize.min.js:

Teraz działa. Jednak nie jest to bezpieczne rozwiązanie i lepiej zastosować to wyżej (z listą i dodawaniem znaku <br /> już w samym kodzie HTML, a nie poprzez funkcję).

Problem: duplikaty

To by było na tyle tego wpisu. Ale można zauważyć błąd, który pokazuje się jeśli wpiszemy takie same dane w dwa wiersze: Error: [ngRepeat:dupes]. Zostajemy odesłani do dokumentacji: Error: ngRepeat:dupes. Duplicate Key in Repeater, w której możemy znaleźć rozwiązanie problemu. W dyrektywie ng-repeat musimy dodać  track by $index. Co daje efekt:

O co chodzi? Po prostu nie są dozwolone duplikaty w liście po której chcemy przechodzić (jest to związane z odświeżaniem drzewa DOM, więcej tutaj). Aby umożliwić wstawianie duplikatów, trzeba dodać wyrażenie śledzące poprzez track by wyrazenieSledzace. Wyrażeniem śledzącym musi być jakaś unikalna wartość np. ID. Możemy skorzystać również z $index, czyli kolejno generowane numery podczas pobierania elementów z listy (będziemy z tego korzystać jeszcze nieraz).

Kosmetyczne ukrycie

Na koniec dodajmy małą rzecz, która dużo nie robi, ale dzięki niej przyjemniej będzie się korzystało z aplikacji. Zauważyliśmy pewnie, że wszystkie wiersze są przepisywane (również te puste). Dlatego w funkcji myResult() w kontrolerze dodajmy warunek, który będzie dodawał do listy wyników jedynie, gdy tytuł będzie uzupełniony:

Wynikowy kod

index.html

controller.js

Wynik działania

 

Relacja z Warszawskich Dni Informatyki 2016

Warszawskie Dni Informatyki to wydarzenie, które łączy konferencję o tematyce IT, warsztaty oraz giełdę pracy. Jest to wydarzenie zarówno dla studentów, jak i profesjonalistów. W tym roku WDI odbyło się w dniach 22-23 marca w gmachu Wydziału Matematyki i Nauk Informacyjnych Politechniki Warszawskiej.

Panel Rektorski

W przeddzień konferencji odbywa się Panel Rektorski w Senacie Rzeczypospolitej Polskiej. Jest to zamknięte wydarzenie dla zaproszonych gości i słuchaczy. Wśród nich byli ministrowie, rektorzy warszawskich uczelni, przedstawiciele władz, firm i innych wyróżnionych organizacji. Oczywiście nie wszyscy się pojawili (odniosłem wrażenie, że było mniej gości niż w poprzednim roku). Podobnie jak w poprzednim roku zostałem na niego zaproszony (jak również inni z Koła Naukowego Informatyków Genbit), za co dziękuję organizatorom, a szczególnie Michałowi Bijacie.

Tematyka dyskusji dotyczyła trendów technologicznych w informatyce. Rektorzy przedstawiali technologie lub typy produktów, w których jest miejsce na innowacje i możliwość osiągnięcia sukcesu w ciągu najbliższych lat.

  • Poruszonym, ostatnio modnym obszarem były m.in. internet rzeczy (ang. Internet of Things – IoT) oraz Big Data.
  • Ciekawym tematem była również rekrutacja online z wykorzystaniem wideo. Duże firmy zatrudniają wielu pracowników, a ich rotacja może być dosyć duża. Musi być przeprowadzonych wiele rozmów, które generują koszty i zabierają dużo czasu. Sprawdzenie umiejętności online i przeprowadzenie rozmów przez Internet może trochę pomóc w rozwiązaniu tego problemu. Kandydat na pracownika nie musiałby przyjeżdżać do siedziby firmy, co pozwoliłoby im oszczędzić czas i pieniądze na dojazdach oraz mogliby wziąć udział w większej liczbie rozmów, aby wybrać odpowiedniejszą firmę dla siebie. Zaś rekruterzy mogliby lepiej zorganizować więcej rozmów. Wstępne test online mogłyby pomóc w początkowej ocenie kandydatów. Zauważam jednak również wady takiej formy rekrutacji: nie ma bezpośredniego kontaktu z kandydatem, nie ma pewności co do samodzielności rozwiązywania testów, a kandydat nie ma okazji zobaczyć firmy od środka. Według mnie rekrutacja w takiej formie mógłby być zastosowana głównie jako etap wstępny (bo ogłoszenia często pozostawiają wiele do życzenia, po prostu nie zawierają wielu szczegółów, pozwoliłoby to na początkowe poznanie obu stron).
  • Poruszona została również tematyka edukacji w szkołach odnośnie informatyki. Firmy IT brały udział w WDI, a szczególnie Giełdzie Pracy IT, głównie po to, aby zdobyć pracowników. Kandydatami są absolwenci uczelni lub studenci. Ich umiejętności zależą od uczelni (oczywiście po za zdobywaniem umiejętności na własną rękę), ale to czego mogą się nauczyć jest związane z tym co już umieją. I tutaj jest zadanie szkoły. Od nich w dużej mierze zależy co będą potrafić kandydaci na studia i czy w ogóle pójdą na informatykę. Uczniowie techników informatycznych zazwyczaj mają większe praktyczne umiejętności i zdobyli podstawy np. programowania, administrowania itd. Absolwenci liceów, szczególnie o profilu matematyczno-fizycznym, mają szansę mieć więcej wiedzy z zakresu nauk ścisłych. Jednak w pozostałych klasach, nauczanie informatyki pozostawia wiele do życzenia. Ci wszyscy mogą pójść na studia na informatykę – program trzeba dostosować do wszystkich (np. często zaczynając od podstaw programowania, ale z bardzo szybko rosnącym poziomem). We wcześniejszych etapach nauczania z informatyką jest jeszcze gorzej. Godzin jest mało. A jak już są, to jakość przeprowadzanych lekcji często jest bardzo słaba. Winą po części może być negatywna selekcja nauczycieli informatyki – ci lepsi mogą pójść pracować w firmach, w których dostaną dużo większe wynagrodzenie niż w szkołach (z nich zostaną jedynie ludzie z powołania, których jest garstka). Na domiar złego, część z nich uważa, że uczniowie nauczą się sami w domu tego co potrzeba. Tak jednak nie zawsze jest. Jedynie naprawdę zdeterminowane osoby zdobędą wystarczająco przydatnej wiedzy z informatyki.
  • Pokazano również potrzebę na aplikacje dla seniorów. Poza tym co pierwsze w tym miejscu przychodzi na myśl tzn. uproszczenie interfejsu użytkownika i ułatwienie korzystania z aplikacji, zostało przedstawione wymaganie dla takich użytkowników. Chodzi o bezpieczeństwo i stabilność systemu, a także prywatność. Według dyskutantów, starsze osoby bardziej przykładają uwagę do tych czynników.

Są to obszary, w których jest jeszcze coś do zrobienia. Tematy zostały jedynie zasygnalizowane.

Tematy prezentacji

W tym roku było kilka ścieżek tematycznych z wieloma prelekcjami. Przedstawię najciekawsze informacje, które udało mi się wychwycić.

  • Wykłady rozpoczęły się prezentacją od jednego ze sponsorów Jak uprawia się IT? Asseco Keynote (Artur Wiza w zastępstwie Witolda Maliny). Poza informacją o firmie powtarzaną co roku (zaczynali od oprogramowania do małych banków spółdzielczych, a potem łączyli się z innymi, stając się coraz większym graczem na rynku – tą taktykę widać do dzisiaj) omówione zostało zastosowanie informatyki na przykładzie rolnictwa. Dla analityka IT ważne jest to, aby specjalizował się w jakimś dodatkowym obszarze, aby miał wiedzę dziedzinową.
  • Kolejną prezentacją była Accenture Technology Vision (Jacek Borek). Dotyczyła trendów w branży IT na rok 2016: Inteligentna automatyzacja (Intelligent Automation), Elastyczność pracy (Liquid Workforce), Platformy biznesowe (Platform Economy), Innowacje zmieniające porządek na rynku (Predictable Disruption) i Cyfrowe zaufanie (Digital Trust). Zostały one wymienione i krótko omówione. Pełen raport w języku angielskim można znaleźć tutaj.
    Bardzo podobna prezentacja raportu była w poprzednim roku. Trendami na 2015 były: Internet osobisty (Internet of Me), Przewidywania oczekiwania klientów przez technologię (Outcome Economy), Firmy w sieciach biznesowych (Platform (R)evolution), Wzrost IQ firm (The Inteligent Enterprise) i  Roboty w zespole (Workforce Reimagined). Raport jest tutaj. Możemy porównać na ile przewidywania się spełniły.
  • Następnie byłem na wykładzie Przegląd rozwiązań real-time messaging i platforma integracyjna nowej generacji firmy TIBCO zaprezentowanym przez kilka osób z firmy (m.in. Michał Jakóbczyk, Łukasz Antoniak). Były omówione technologie do wymiany wiadomości pomiędzy aplikacjami w czasie rzeczywistym: TIBCO Rendezvous, EMF, FTL. Ale ciekawsze było omówienie produktu BusinessWorks 6 do tworzenia aplikacji. Podczas prezentacji zostało stworzone w nim demo (publikowanie wpisów na Twitterze), aby pokazać jego możliwości. Praca w nim polega na przeciąganiu odpowiednich klocków, aby budować aplikację. Jest duży wybór (m.in. usługi REST, integracja z bazami danych itd.), a to czego nie ma, można dopisać samemu w języku Java.  Pytałem czy jest wspierany język Scala – dostałem odpowiedź, że nie (oraz dosyć niepochlebne informacje na temat tego języka w wykorzystaniu w projektach). Narzędzie wygląda dosyć przyjaźnie. Na pytania o narzut w stosunku do aplikacji stworzonej bez tego narzędzia, firma odpowiadała, że jest on bardzo mały, a wydajność duża.
  • Prezentację na którą osobiście liczyłem, że dowiem się z niej dużo była: Jaka wiedza i narzędzia są niezbędne Analitykowi Biznesowemu? (Piotr Aftewicz). W internecie, książkach, na studiach jest bardzo dużo materiałów dla programistów. Dla analityków jest tego zauważalnie mniej (chociaż istnieje kilka dobrych książek w języku polskim). Forma prezentacji była dosyć specyficzna. Zamiast omawianych po kolei slajdów, prelegent wymyślił kilkanaście pytań, które umieścił na slajdach, a ich numery rozdał publiczności na kartkach. Publiczność miała mówić numery, a prowadzący odpowiadać na „wylosowane” pytania. Na początku budziło to zainteresowanie i było ciekawe. Dodatkowo świetnie zgrało się z omawianą tematyką (pracą analityka w dużej mierze jest zadawanie pytań). Jednak już po chwili można było zauważyć wadę takiego rozwiązania. Pierwsze pytania, w kolejności numeracji, były podstawowe („Kim jest analityk?”, „Na czym polega jego praca?”), zaś te o większych numerach odnosiły się już do szczegółów (np. „Jakich narzędzi użyć do przechowywania dokumentacji i jej wersjonowania?”). Pytania padały w kolejności losowej, a więc, aby odpowiedzieć na szczegółowe pytanie, trzeba było między wierszami odpowiedzieć na te podstawowe. A jak wreszcie trafiło się któreś z tych o niższej numeracji, to tak naprawdę odpowiedź na nie już padła (chociaż z drugiej strony było to niejakie podsumowanie). Forma prezentacji była ciekawa, jednak aby ją wykorzystywać, należałoby opracować pytania, które mogą być zadane w dowolnej kolejności. Dodatkowo łatwo było odbiec od zadanego pytania, przez to organizacja prezentacji była czasem trochę zaburzona. Mimo tego, dowiedziałem się podstaw, w jaki sposób działa zespół analityków w firmie Billenium. Zauważyłem tu podobieństwo w pracy jako audytor bezpieczeństwa informacji. W obu przypadkach trzeba drugą stronę dokładnie wypytać, uważnie słuchać, trzymać się tematu, starać się uzyskać konkretne odpowiedzi na pytania, najlepiej pracować we dwie osoby (jedna rozmawia, a druga robi notatki), a przy tym zachować wszystkie oczywiste standardy pracy z klientem (dobra atmosfera, schludny wygląd itd).
  • W drugim dniu była cała Ścieżka DevTalk.pl. Większość z tematów dotyczyła C# i .NET. Spotkać można było tam również Maciej Aniserowicza (organizator konkursu Daj Się Poznać, w którym biorę udział), który zapowiedział pierwszy wykład ze ścieżki.
  • Pierwszym wykładem ze Ścieżki DevTalk.pl był ASP.NET Core + Docker (Jakub Gutkowski). Na początku było pokazane krótkie demko jak uruchomić aplikację w ASP.NET Core na Macu. Jednak główna przekazywana informacja, to to że Microsoft pracuje nad nową wersją ASP.NET Core. To co jest obecnie ma być zmieniane i lepiej poczekać z nauką, aby wejść od razu na stabilne środowisko. W dniu prezentacji nie było wiadomo kiedy to nastąpi. Chociaż tu nie ma zaskoczenia ze strony Microsoftu, bo czasem następują różne dziwne działania w stosunku do programistów korzystających z ich produktów (np. zaprzestanie wsparcia XNA, mimo że wiele osób nadal z niego korzysta).
    W drugiej części tego wykładu zaprezentowane było środowisko Docker. To narzędzie nie tylko dla programistów .NET. Według prezentacji Docker to wygodne środowisko do tworzenia i uruchamiania aplikacji (przydatne w nauce nowych języków i technologii – nie musimy instalować niczego nowego). Jeśli kiedyś chcieliśmy mieć gotowe, skonfigurowane środowisko uruchomieniowe do szybkiego odtworzenia, musieliśmy tworzyć maszynę wirtualną. Docker działa w trochę inny, dużo lżejszy sposób (nie jest wirtualizowany cały system, a jedynie środowisko). Dodatkowo jest oparty na warstwach, co pozwala na doprecyzowywanie konfiguracji. Gotowe paczki są dostępne na Docker Hub, jednak nic nie stoi na przeszkodzie, aby tworzyć własne.
  • Kolejną prezentacją, którą wysłuchałem Jak przewidzieć awarię elektrowni przy pomocy narzędzi Big Data? (Sebastian Dziadkowiec, Łukasz Sidor) również była ze Ścieżki DevTalk.pl, jednak tym razem już nie dotyczyła .NET-a. Omówione zostały sposoby w jaki Accenture radzi sobie wykrywaniem awarii urządzeń. Nie tylko w elektrowniach, ale we wszystkich fabrykach i zakładach produkcyjnych. Obecnie wiele urządzeń posiada czujniki, z których można zbierać dane. Jednak są one najczęściej wykorzystywane, aby powiadomić o awarii, która nastąpiła. To przedstawione podejście mówiło o tym, żeby przewidywać awarie zanim one nastąpią. Dzięki temu wyeliminuje się przerwy w produkcji i zmniejszy straty. W tym celu należy opracować model i na podstawie analizy dużej ilości danych (tutaj przydaje się Big Data) wywnioskować kiedy awaria może nastąpić, aby jej zapobiec i np. skierować do wcześniejszego serwisowania. Po za danymi z czujników są brane różne informacje, które mogą mieć wpływ na wyniki (np. informacje od producenta na temat częstotliwości koniecznych konserwacji). Okazuje się, że brakującymi składowymi w modelu mogą mieć również czynniki środowiskowe, na które na pierwszy rzut oka nie mają związku.
    Ten temat kojarzy mi się z Business Intelligence w produkcji (właśnie tam chodzi o to aby analizować zbierane dane i uzyskiwać z nich cenne informacje – w tym obszarze jest jeszcze wiele do zrobienia) oraz systemami klasy MES (Manufacturing Execution System).
  • Kolejnym ciekawym tematem był Software w powietrzu, czyli systemy bezzałogowe w Asseco (Tomasz Mosiej). Przedstawiony został system dla bezzałogowych statków powietrznych (tu prelegent przestrzegał, aby nie używać nazwy „dron” używanej w mediach). Zawierało ono m.in. moduł zdalnego sterowania, monitorowanie lotu, sztuczny horyzont, planowanie trasy, mapę z dozwolonymi miejscami w których można latać, wykorzystanie wielu monitorów, symulator do testowania oprogramowania lub celów treningowych itd. Wśród głosu z sali można było usłyszeć, że system jest bardzo podobny do wcześniejszych rozwiązań innych firm (np. chińskich). Jako kontrargument padły stwierdzenia, że ten prezentowany system jest uniwersalny (może być stosowany do różnych bezzałogowych statków powietrznych, a nie tylko do wybranych modeli) i że nie da się zrobić systemu, który wygląda inaczej, a ma spełniać daną funkcjonalność.
  • Była również prezentacja pt. Jak rozpocząć przygodę z AngularJS? Dariusza Kalbarczyka (współautora książki AngularJS. Pierwsze kroki, którą polecam), jednak zainteresowanie było tak duże, że niestety nie mogłem w niej uczestniczyć.

Giełda Pracy IT

Stoisk z ofertami pracy w IT było wiele. Jak doskonale wiemy, pracownicy z tej branży są mocno poszukiwani. Przeważały oferty dla programistów. Zarówno Java jak i C#. Ofert .NET było trochę więcej w stosunku do poprzedniego roku (być może to zasługa dobrego marketingu Microsoftu oraz informacji o nowej ścieżce tematycznej na WDI związanej z .NET-em, która dotarła do działów HR). Spotkać można też było PHP, oferty dla frontendowców i inne.

Oczywiście były stoiska sponsorów WDI: Asseco, Accenture, Pracuj.pl, Goldman Sachs. Asseco przygotowało dosyć duże, jednak trudno było dowiedzieć się na nim konkretnych informacji po za dostaniem ulotki i informacji o stronie internetowej z ofertami (co ciekawe, szukają programisty COBOL-a). Podobnie było w Accenture. Być może tylko taki był cel, aby kandydatów zachęcić do przejrzenia ofert. Było również stoisko Billenium, jednak sporo mniejsze w stosunku do poprzedniego roku. Udało mi się dowiedzieć, że szukają programistów .NET, a javovcom mogą zaproponować tylko outsourcing. Firmą specjalizującą się tylko w .NET była też Netwise. Chwalą się, że mają dobry kontakt z Microsoftem, wykorzystują i wdrażają Microsoft Dynamics, nie są „korpo”, mają świetne miejsca pracy oraz ich pracownik ostatnio opublikował artykuł w Programiście (Budowa aplikacji .NET wykorzystującej system Microsoft Dynamics CRM jako repozytorium danych – 02/2016). Netware wywołał dosyć pozytywne wrażenie (gdybym szukał pracy jako programista .NET to mógłbym wziąć ich pod uwagę), ale może to tylko zasługa dobrego działu HR i sprzedaży (hotdogów na targach pracy to jeszcze nie widziałem). Dział HR Samsunga chyba wziął sobie mocno do serca zaciekawienie potencjalnych kandydatów. Na stoisku owszem było zainteresowanie, ale jednak bardziej niż ofertami pracy to wystawionymi łamigłówkami (rozplątywanie sznurków, metalowych prętów, optymalne ułożenie klocków itd. – swoją drogą bardzo pomysłowe). Na miejscu była również firma Predica organizująca bardzo ciekawy konkurs (bardzo popieram takie działania dające możliwość wykazania się studentom!). Intel jak zawsze szukał programistów niskopoziomowych (pisanie sterowników itd.). Co ciekawe, pojawił się również CD Project RED. Zaś SAS po za ofertami pracy zachęcał studentów do wzięcia udziału w Akademii Młodych Talentów (szkolenia w wakacje z produktów SAP). Były też inne stoiska wielu firm, jednak stosunkowo mniej widoczni (np. Pretius).

Na uwagę zasługuje również stoisko Pracuj.pl. Na jednym prezentowali swoją aplikację mobilną do szukania pracy Hunt Me. W według mnie to niezbyt trafiony pomysł. Jak ktoś chce znaleźć pracę, to może usiąść do komputera i skorzystać z wersji w przeglądarce internetowej. Możliwość o decydowaniu o ofertach pracy i aplikowaniu na nie np. podczas podróży nie jest koniecznością. Lepiej przemyśleć swój wybór na spokojnie. Jednak na drugim stoisku były osoby z Pracuj.pl, które pomagały w ocenie CV. Według mnie to świetny pomysł. Niby w Internecie jest już wiele informacji na ten temat. Ale jak spojrzenie kogoś bardziej doświadczonego na konkretny przypadek może pomóc osobie początkującej. Co prawda na innych giełdach pracy można to częściej spotkać, ale fajnie, że pojawiło się też na WDI.

Organizacja i podsumowanie

Jak co roku odbyły się liczne konkursy. Na przykład ten z zaproszeniem jak największej ilości osób na WDI (liczą się tylko te osoby, które się potem zarejestrują) czy dronami do wygrania. Muszę przyznać, że reklama zawsze stoi na wysokim poziomie. Podczas WDI można było zjeść kawałek pizzy. Aby to zrobić trzeba było zebrać 4 osoby. Zawsze to jakiś sposób na integrację uczestników. W giftbagach jak zawsze legendarne koszulki WDI.

Jeśli chodzi tylko o studentów, to organizatorzy WDI wystawiają zwolnienia z zajęć dla kilku warszawskich uczelni. Myślę, że jednak i w innych, okolicznych uczelniach nie powinno być problemu, aby samemu się zwolnić z zajęć na WDI. Prowadzący zajęcia, którym zależy na dobru studentów powinni zrozumieć, że przez takie dwa dni wykładów, otrzymają tyle praktycznej wiedzy, której nie zaoferuje żadna uczelnia. Owszem, podstawowa wiedza też jest bardzo ważna. Ale poświecić tych kilka standardowych wykładów dla WDI się po prostu opłaca (najlepszą sytuacją jest, gdy większość rocznika jedzie, wtedy zajęcia można przełożyć, aby odrobić np. w innym terminie – w takiej sytuacji student nic nie traci).

Wadą organizacyjną były długie kolejki. Od kiedy wprowadzono dodatkowe gadżety dla iluś pierwszych osób na rejestracji, długość kolejki diametralnie wzrosła. Można było to ominąć np. rejestrując się później (np. dopiero po drugim wykładzie), jednak nie każdy o tym wiedział. Czasem kulała też informacja np. o tym w której sali jaki wykład albo o zmianach w agendzie (zdarzało się, że część uczestników trafiła na inny wykład niż myślała). W stosunku do poprzedniego roku sala organizatorów była w drugim budynku (odbiór pizzy i giftbagów), co skutkowało, tym że uczestnicy musieli czasem postać na dworze w kolejce. Jednak przy tak dużym przedsięwzięciu i tak było dobrze. Naprawdę wielu ludzi musiało poświęcić dużo czasu, aby przygotować tak duże wydarzenie. Gratuluję udanej współpracy z firmami i zaproszenia dobrych prelegentów.

Trochę historii

Pierwsze WDI na którym byłem to edycja w 2013 roku i od tego czasu jeździłem już zawsze razem z innymi członkami z Koła Naukowego Informatyków Genbit (w tym roku zostało partnerem WDI). Wielu z nich właśnie tam znalazło pracę. W 2013 odbyła się trzecia edycja, także chronologia WDI wygląda następująco:

Z poprzednich lat, prezentacje, które zapadły mi w pamięć, to m.in.:

  • WDI 2014: Czy informatyka ma przyszłość? (Adam Góral, Prezes Zarządu Asseco Poland). Mimo że było to wystąpienie sponsora (wiadomo, opis firmy), to było naprawdę dobre. Pokazanie jak zaczynali, w jakich warunkach musieli pracować. Na początku byli kilkoma studentami i duże banki nie chciały z nimi współpracować. Znaleźli niszę: małe banki spółdzielcze. Gdy zarobili, zainwestowali, rozrastali się, wchłaniali inne firmy i łączyli się (widać tę strategię nadal jak po prostu przejmują konkurencję). Dopiero wtedy, jako duży gracz, mogli współpracować z innymi równymi sobie. To przykład, że polska firma może osiągnąć sukces. Jednak obecnie mamy trochę inne realia. Na rynku jest już duża konkurencja i ten sposób teraz prawdopodobnie by się nie sprawdził. Po prostu był to odpowiedni człowiek, w odpowiednim czasie, na odpowiednim miejscu.
  • WDI 2014: Panel Dyskusyjny Big Data – prowadzącym panel był prof. Bolesław Szafrański, zaś dyskutującymi: Tomasz Grabowski (Senior Manager Działu Analizy Accenture), Wiesław Wyszogrodzki (Menedżer Rozwoju Biznesu w Sygnity), Mariusz Dzieciątko (SAS Institute Polska), dr Kamil Kulesza (Centrum Zastosowań Matematyki i Inżynierii Systemów PAN), Jannusz Dygaszewicz (Dyrektor Programowania i Koordynacji Badań, GUS). To był niezły pokaz jak powinien wyglądać panel dyskusyjny. Dobrze przygotowane pytania, moderacja, podsumowania. Dobrze się słuchało i zapamiętywało informacje. Wtedy tematyka Big Data stawała się modna. Na wiele pytań nie było jeszcze odpowiedzi i dyskutujący dopiero starali się coś wymyślić i wypracować wspólną odpowiedź, trochę na zasadzie konsensusu i podsumowaniu prowadzącego. Było pytanie czym tak naprawdę jest Big Data (wtedy odpowiedź nie całkiem oczywista dla wszystkich). Innym pytaniem było to czy da się termin „Big Data” dobrze przetłumaczyć na język polski. Padło kilka propozycji, jednak nie było zgodności co do jednego, najlepszego i zadowalającego wszystkich. Być może to właśnie wtedy w Polsce nastąpiła historyczna chwila, że zdecydowano na „Big Data” mówić właśnie tak, a nie np. „Duże Dane”.
  • WDI 2013: Bioinformatyka – jak komputery pomagają opisać i zrozumieć żywy organizm, WDI 2014: Bioinformatyka – komputerowy klucz do genomu (dr Bartek Wilczyński) – dwa podobne wykłady (trochę się różniły, jednak nie pamiętam co było w którym) o zastosowaniu informatyki w biologii. Obecnie coraz ważniejszą rolę odgrywa biologia molekularna. Kiedyś trudnym zadaniem było sekwencjonowanie pojedynczego genomu człowieka czy nawet zwierząt. Teraz robi się to dla tysięcy ludzi. Istnieją już nawet firmy specjalizujące się w takich usługach do prywatnych zastosowań. Ilość danych przybywa bardzo szybko. Jednym z zadań bioinformatyki jest ich analiza. Na tym wykładzie pierwszy raz usłyszałem o grze Foldit, o której dopiero później zaczęto częściej mówić na innych wykładach czy w mediach. Polega ona na zwijaniu białek, żeby uzyskać jak najlepszy lub nowy, nieznany efekt. Może to pomóc w opracowaniu lekarstwa na daną chorobę. Znalezienie optymalnego rozwiązania tego typu problemów jest dla komputerów bardzo trudnym zadaniem. Dlatego stworzono grę, w której gracze z całego świata mogą pomóc poprzez po prostu granie. Kojarzy mi się to trochę z projektem BOINC (kiedyś SETI@home), w którym użytkownicy z całego świata udostępniają część mocy obliczeniowej swoich komputerów, aby rozwiązywać ważne problemy (tylko tu z tą różnicą, że udostępnia się „moc” swojego umysłu, a dokładniej umiejętność rozwiązywania problemów). Bardzo ciekawie słuchało się tych prelekcji. Może dodatkowo dlatego, że mnie osobiście interesuje ta tematyka (chociaż nigdy się w nią bardziej nie wgłębiałem).
  • WDI 2014: Internet rzeczy. Jaka będzie sieć przyszłości? (Mateusz Mikulski) – przemyślenia na temat IoT. Pokazanie realnego zastosowania, że można tego rzeczywiście używać, a to nie tylko puste hasła reklamowe niektórych firm i produktów.
  • WDI 2014: Tworzenie mobilnych gier HTML5 na Firefox OS, WDI 2015: Gry HTML5? To proste! (Andrzej Mazur) – omówienie tworzenia gier w HTML5 i JavaScript. Dzięki temu można je uruchomić na tanich telefonach z systemem operacyjnym Firefox OS od Mozilli. Wtedy było dosyć głośno o tym systemie, obecnie jednak temat ucichł. Ciekawostką podczas prezentacji było to, że pokaz slajdami był sterowany za pomocą pada.
    Z Kołem Naukowym Informatyków Genbit udało nam się zaprosić tego prelegenta na  konferencję Inżynierii Gier Komputerowych XI 2014.
  • Ransomware – wymuszanie okupu w sieci (Jarosław Sordyl, Europol) – omówienie zagrożeń i ataków, których akurat w tym czasie było nasilenie. Między innymi podszywanie się pod policję czy Cryptolocker, który żądał okupu. Ważną informacją do zapamiętania było to, żeby nikt nigdy nie wpłacał pieniędzy cyberprzestępcom, gdyż to jest po prostu wspieranie ich i przez to ataki są coraz częstsze i groźniejsze.
  • WDI 2014: Biosensoryka – wykorzystanie sensorów medycznych w technologiach mobilnych, WDI 2015: Mobilne narzędzia wsparcia działania pojedynczego żołnierza (mjr dr inż. Mariusz Chmielewski) – prezentacja realnych zastosowań opracowanych aplikacji mobilnych m.in. do przetwarzania danych z sensorów oraz monitorowania medycznego (np. włączenie alarmu gdy osoba dostanie ataku padaczki lub straci przytomność i się przewróci).
  • WDI 2015: Lepsze algorytmy = szybsza aplikacja (prof. dr hab. Krzysztof Diks) – prelegent jest współautorem znanej książki Algorytmy i struktury danych. Co do samej prezentacji, było to omówienie klasycznych algorytmów np. rozwiązującego Wieże Hanoi (warto zauważyć, że wraz z interakcją publiczności – ochotnik rozwiązywał łamigłówkę na fizycznych słupkach i krążkach) oraz opracowanych algorytmów do zadań z Olimpiady Informatycznej.
  • WDI 2015: Warsztaty druku 3D – czyli od pomysłu do realizacji (firma Kombi3D) – w sumie to był wykład na temat technologii druku 3D (spodziewałem się bardziej praktycznych warsztatów) z pokazem już wydrukowanych modeli. Zrobili też pokaz drukowania 3D na korytarzach podczas WDI. Mogłem porównać sprzęt z tym, na którym pracowałem w Instytucie Informatyki na UPH.

Jak widać, nawet po kilku latach trochę wiedzy zostało trochę wiedzy w głowie. Po wyjściu z dobrej prezentacji umysł jest pełen pomysłów. Wysłuchanie doświadczeń innych jest bardzo inspirujące.

Nie pozostaje mi nic innego, tylko czekać na kolejną edycję Warszawskich Dni Informatyki i liczyć na świetne prezentacje. Do zobaczenia za rok!

Jeśli pomyliłem jakieś fakty lub źle zinterpretowałem słowa prelegenta (szczególnie jeśli tu trafiłeś i jest mowa o Tobie), to proszę o informację, najlepiej na e-maila, abym mógł to poprawić. Informacji było dosyć dużo, sprzed kilku dni, a nawet lat. Dodatkowo, jeśli ktoś dysponuje slajdami z prezentacji o których mowa, ich udostępnienie też byłoby wartościowe. 

Kontroler w AngularJS

Znajdziecie tutaj szablon aplikacji w AngularJS. W poprzednim wpisie co prawda jest już Hello World, ale teraz napiszemy je z podziałem na pliki, kontrolerem i modułem, tak jak powinno to się robić w prawdziwych aplikacjach. Poznamy także czym jest obiekt $scope.

Hello World w jednym pliku

Przypomnijmy sobie kod Hello Word:

Wynik działania:

Podział na pliki

Teraz nasza aplikacja będzie składała się z dwóch plików:

  • index.html – zawiera widok w HTML,
  • controller.js – zawiera kontrolery (w tym przypadku również deklarację modułu) w JavaScript.

Pozwoli to zachować porządek w kodzie (HTML nie będzie się mieszał z JavaScript). W przyszłości, gdy kontrolerów będzie więcej, można tworzyć kolejny plik dla każdego kontrolera, co jeszcze bardziej zorganizuje kod aplikacji.

Moduł

W AngularJS można aplikacje dzielić na moduły. Na początku wystarczy nam jeden. Jego deklaracja wygląda tak:

Pierwszym parametrem jest nazwa deklarowanego modułu, a drugim lista wstrzykiwanych zależności (o tym w kolejnych wpisach – na razie nie potrzebujemy nic dodatkowego).

W kodzie HTML musimy teraz zainicjalizować naszą aplikację za pomocą dyrektywy ng-app (było już trochę o niej w poprzednim wpisie). Tym razem przyjmie parametr z nazwą naszego modułu. Umieszczono ją także w elemencie <html>:

Kontroler

AngularJS wspiera tworzenie aplikacji zgodnych ze wzorcem projektowym Model-Widok-Kontroler (ang. Model-View-Controller, MVC). W kontrolerem jest javascriptowa (anonimowa) funkcja:

Musimy jednak kontroler przypisać do modułu. Służy do tego metoda controller wywoływana na zmiennej pod którą jest obiekt modułu (w tym przypadku app), która przyjmuje dwa parametry. Pierwszym jest nazwa kontrolera, a drugim kontroler (czyli funkcja):

W HTML należy także zastosować dyrektywę ng-controller, aby powiązać kontrolerem w widokiem (wybranym tagiem HTML). Zazwyczaj jest to tag <body>, ale może być również jakiś <div>. Ważne jest to, aby był to nadrzędy tag do tych, w których ma działać Angular. Parametrem jest nazwa kontroler (podobnie jak w przypadku dyrektywy ng-model):

Implementacja kontrolera – korzystanie ze $scope

Na potrzeby przykładu dodajmy w kontrolerze operację, która będzie ustawiała wartość zmiennej myText. Musimy jednak jakoś się do niej dostać, gdyż jest dostępna tylko w widoku. Do tego potrzebny będzie nam obiekt $scope. Jest to most pomiędzy widokiem a kontrolerem. Tworzony jest automatycznie podczas wywołania dyrektywy ng-controller. Aby z niego skorzystać, należy go wstrzyknąć do kontrolera (przekazać jako parametr do funkcji):

Zmiany, które zajdą w widoku będą automatycznie zachodziły w kontrolerze i w drugą stronę – modyfikacja w kontrolerze zmienia dane w widoku.

W kontrolerze dodajmy jeszcze funkcję o nazwie myResult, która będzie korzystać ze zmiennej myText, wykonywać operacje (dodawanie kawałka tekstu) i zwracać tekstowy wynik. Przypiszmy ją do $scope, aby była dostępna w widoku:

Możemy teraz w widoku z niej skorzystać (zauważmy, że jest to interpolacja wywołania funkcji, a nie interpolacja zmiennej):

Wynikowe pliki

index.html

controller.js

Wynik działania aplikacji:

Kod na GitHub

Kod tej części aplikacji umieściłem na GitHubie w repozytorium agenda-editor w  branchu hello-world-angularjs:
https://github.com/mkczyk/agenda-editor/tree/hello-world-angularjs