Polub bloga na fejsie!

KnockoutJS – obserwowalna tablica obiektów obserwowalnych

1

Knockoutjs jest javascriptowym frameworkiem, pozwalającym na wprowadzenie w obrębie interfejsu użytkownika, wzorca MVVM (Model View ViewModel) – w ramach projektu, przy którym obecnie pracuję często go stosujemy – warto się z nim zapoznać (więcej o knockoutjs tutaj). W wielkim skrócie, pozwala on na „podpięcie” elementów interfejsu, takich jak na przykład textbox’y, do modelu danych – aktualizacja wartości w tak podpiętym textbox’ie powoduje aktualizację wartości w modelu, a co za tym idzie w innych elementach UI podłączonych do tego modelu.

Problem

Wartości modelu, które możemy aktualizować, nazywane są obiektami obserwowalnymi (jest to w zasadzie javascriptowa implementacja wzorca obserwator). Możliwe jest również obserwowanie tablic – niestety nie działa to w sposób w jaki często by się nam przydało – cytat z dokumentacji: „Key point: an observableArray tracks which objects are IN the array, NOT the state of those objects„. Co więc w przypadku, kiedy jednak chcielibyśmy obserwować stan obiektów w tablicy? Należy użyć tytułowej tablicy obserwowalnej zawierającej obserwowalne obiekty.

Przykład

Weźmy prosty przykład: chcemy wyświetlić tablicę z dwoma kolumnami (imię i liczba), z możliwością usuwania wierszy z tabeli oraz z podsumowaniem (imiona i suma liczb). Poniżej fragment kodu HTML:

Najpierw zwróćmy uwagę na tag ‚tbody’ – mamy tutaj podpięcie ‚foreach’ do tablicy obserwowalnej ‚rows’ – binding ten pozwala na wyrenderowanie wszystkich tagów znajdujących się wewnątrz aktualnego tagu, tyle razy ile elementów znajduje się w tablicy. Dodatkowo, wewnątrz tagu ‚tbody’ (rodzica), mamy dostęp do nazwanych elementów tablicy: spójrzmy na dwa tagi input – pierwszy podpina atrybut ‚value’ tagu input do wartości ‚name’ nazwanego elementu ‚row’; w drugim tagu ‚input’, również mamy binding do atrybutu ‚value’ – tym razem podpinamy wartość ‚amount’.

W trzeciej kolumnie naszej tabeli mamy tag typu kotwica – (‚a’ z atrybutem href ustawionym na #). W tym przypadku korzystam z kolejnej ciekawej funkcjonalności knockouta czyli podpinania funkcji pod zdarzenia elementów DOM – w tym przypadku do zdarzenia ‚click’ bindujemy funkcję ‚removeRow’ (odnosimy się do niej poprzez zmienną kontekstu ‚$parent’, która wskazuje na kontekst poza poza obecnym kontekstem).

Na samym dole dwa bindingi do atrybutu ‚text’ tagu ‚p’ (text jest bindingiem, który ustawia nie tyle atrybut tagu co wartość innerText/textContent elementu DOM) – tym razem podpinamy się nie do obiektów obserwowalnych, a do „obserwowalnych funkcji wyliczalnych” (w knockoucie, funkcje takie, zależą od obiektów obserwowalnych, i są przeliczane za każdym razem gdy wartość zmiennej obserwowalnej się zmieni).

Implementacja

Html przygotowany, czas przejść do skryptu – zacznijmy od utworzenia view modelu i dodaniu do niego opisywanej tablicy obserwowalnej:

Na początku szybko rozważmy przypisanie

Jest to popularna konwencja stosowana w skryptach operujących na knockoucie – słowo kluczowe this jest często redefiniowane na przykład w funkcjach (także gdy razem z knockoutem używamy jQuery), dlatego w obrębie stosując ‚self’ zamiast możemy łatwo uniknąć pomyłek (przykład użycia this wewnątrz funkcji za chwilę).

Przejdźmy wreszcie do tablicy – jak widać, mamy tutaj przypisanie do zmiennej ‚rows’ wartości zwracanej przez metodę observableArray (należącej do klasy ‚ko’ – w ten sposób odwołujemy się do wszystkich funkcjonalności knockouta) – w tym momencie, każdy binding do tej tablicy, będzie reagował na zmiany ilości elementów w tej tablicy. Funkcję ‚observableArray’, wywołujemy przekazując do niej wartość początkową – w naszym przypadku jest to tablica obiektów ‚row’: każdy z nich zawiera właściwości name i amount – wartości te są zmiennymi obserwowalnymi (ko.observable) – dzięki temu możemy obserwować zmiany poszczególnych wartości w tablicy (zmieniać może je użytkownik, aktualizując wartości textbox’ów w tablicy), co wykorzystamy za chwilę do sumowania wartości amount i sklejania imion.

Sumowanie

Przejdźmy zatem do implementacji sumowania – do naszego view modelu dodajemy funkcję:

Do zmiennej ‚sum’, przypisana jest wartość zwracana przez metodę ‚computed’ knockouta – przekazujemy do niej funkcję wykonującą sumowanie wartości amount poszczególnych elementów tablicy obserwowalnej, oraz zmienną ‚self’ (po to by knockout znał kontekst view modelu). Warto tutaj zwrócić uwagę na metodę arrayForEach knockouta – pozwala ona na wykonanie funkcji przekazanej w drugim jej parametrze dla każdego z elementów tablic przekazanej w pierwszym parametrze. Knockout oprócz arrayForEach, dostarcza kilka przydatnych funkcji do manipulowania obiektami obserwowalnymi – o pozostałych można poczytać na blogu Knock Me Out Ryana Niemayera (polecam!).

Funkcja names

Druga z funkcji wyliczalnych, wygląda następująco:

Jak widać, funkcja bardzo podobna do poprzedniej – zamiast zwracać sumę liczb, zwracana jest list imion, oddzialona spacją. Opisane funkcje, tak jak to zostało opisane przy listingu dotyczącym kodu html, reagują na każdą zmianę imienia lub liczby w wierszach wyświetlanych w tablicy.

Usuwanie wierszy

Pozostał nam już tylko opis usuwania wierszy z tablicy (zdarzenie ‚click’ i przypięta do niej funkcja ‚removeRow’):

Ta funkcja nie jest obserwowalna, ponieważ nie musi się aktualizować za każdym razem kiedy wartość obserwowalna ulegnie zmianie. W wywołaniu usuwania wartości z tablicy widzimy, że użyłem ‚this’ – w tym przypadku pracujemy w kontekście konkretnego wiersza więc ‚this’ oznacza co innego niż ‚self’ – właśnie z tego powodu na początku dokonaliśmy opisanego wcześniej przypisania.

Podsumowanie

Mam nadzieje, że powyższy przykład przyda się komuś, ponieważ w trakcie stawiania pierwszych kroków w knockoucie, zachowanie tablic obserwowalnych nie jest do końca oczywiste – sam trochę się naszukałem gdy po raz pierwszy potrzebowałem zrobić coś podobnego do tego co tutaj opisuję;)

Działająca wersja przykładu dostępna jest tutaj – jeśli ktoś nie zna jsfiddle, polecam się zapoznać – bardzo przydatne do testowania różnych javascriptowych rozwiązań, do tego napisane przez polskiego programistę, Piotra Zalewę!

REACT, REDUX, REACT-ROUTER - KURSY ON-LINE

Chcesz od podstaw poznać tajniki React, Redux oraz react-router? Zapraszam do moich szkoleń on-line:

Przejdź do szkoleń

Uwaga! Obecnie trwa przedsprzedaż kursów - premiera 1 sierpnia 2017!

Google Analytics Alternative