W poprzednich rozdziałach podmieniliśmy dyrektywę playButton
na Custom Element play-button
i, mimo że używamy Angular’owych binding’ów do przekazywania attrybutu src
, wszystko działa jak powinno.
Wynika to z faktu, że AngularJS traktuje nasze custom elementy tak jak każdy inny element DOM. Dopóki nasz komponent prawidłowo reaguje na zmiany atrybutów wszystko będzie w porządku.
Istnieją jednak sytuacje kiedy trzeba pomóc Angularowi zrozumieć jak funkcjonuje komponent. Wcześniej już wspominaliśmy o dyrektywie ng-model
, teraz wyjaśnimy co tak na prawdę dzieje się pod spodem, aby zapewnić Angularowy two-way binding.
Własny <input>
Spójrzmy na nasze pole wyszukiwania, jest to idealny kandydat na stworzenie komponentu <clearable-input>
, który poza samym polem tekstowym, będzie także posiadał przycisk do wyczyszczenia zawartości.
Ciekawostka
Polymer 1.0 ze względów na problemy z implementacją Shadow DOM wstecz oraz z wydajnością zastępuje Shadow DOM nowym pojęciem: Shady DOM.
Zadanie dla Ciebie:
- Zaimplementuj komponent
<clearable-input>
i dodaj go zamiast pola wyszukiwania- Dodaj emitowanie zdarzenia
input
, kiedy pole jest czyszczone- Czy
ng-model
działa?- Pytania?
ng-model
Jak widać ng-model
przestał współpracować.
AngularJS dostarcza wiele dyrektyw niezbędnych do pracy z DOM’em, wśród nich jest zestaw dyrektyw input
, po jednej dla każdego typu. Reagują one na zdarzenia emitowane przez element <input>
i informują ng-model
o zmianach wartości.
Angular nie wie jakie zdarzenia emituje nasz <clearable-input>
i w jakim
polu przechowuje wpisaną wartość. Musimy dodać dyrektywę, która opiszę Angularowi sposób interakcji z komponentem.
Omówiliśmy już opcje dyrektyw restrict
, template
, scope
oraz link
, teraz czas omówić controller
i require
.
controller
Za pomocą controller
możemy przekazać kontroler (lub jego nazwę), który będzie odpowiedzialny za zachowanie dyrektywy. Działa dokładnie tak samo jak parametr controller
przy definiowaniu ścieżek. Sam kontroler otrzymuje jednak dodatkowe usługi:
$element
- element DOM, na którym operuje dyrektywa$attrs
- attrybuty powyższego elementu
require
Za pomocą require
możemy pobrać kontroler innej dyrektywy:
'myDir'
- znajdź kontroler dyrektywymyDir
w tym samym elemencie'^myDir'
- znajdź kontroler w tym elemencie lub jego rodzicach'^^myDir'
- znajdź kontroler w rodzicach aktulnego elementu
Dodatkowo można prefiksować wszystkie z tych opcji ?
, wtedy kontroler nie będzie wymagany - Angular nie rzuci błędem jeśli nie znajdzie wymienionego kontrolera.
Znaleziony kontroler zostanie przekazany naszej dyrektywie jako 4ty argument funkcji link
. Do require
można przekazać też listę takich specyfikacji, wtedy otrzymamy listę kontrolerów.
NgModelController
Dyrektywa ng-model
definiuje swój kontroler NgModelController
, a więc możemy go pobrać za pomocą require
. Jest to niezbędne jeśli chcemy implementować własne elementy otrzymujące dane od użytkownika.
Schemat działania NgModelController
(uproszczony):
- Kiedy użytkownik wpisze coś do pola
<input>
- dyrektywa
input
przechwytuje event i wywołujemodelCtrl.$setViewValue(value)
value
jest przetwarzana przezmodelCtrl.$parsers
imodelCtrl.$validators
, a efekt jest zapisywany jakomodelCtrl.$modelValue
- uruchamiane są wszystkie listenery z
modelCtrl.$viewChangeListeners
, np. wyrażenia podane wng-change="..."
- dyrektywa
- Kiedy zmienia się model
- model przetwarzany jest przez
modelCtrl.$formatters
, efekt jest zapisywany jakomodelCtrl.$viewValue
- wywoływana jest metoda
modelCtrl.$render
zdefiniowana przez dyrektywęinput
- model przetwarzany jest przez
Tak więc, kiedy dodajemy własny rodzaj input’a, potrzebujemy:
- Przechwycić zdarzenia, które wskazują na zmianę wartości i wywołać
modelCtrl.$setViewValue(...)
- Zdefiniować
modelCtrl.$render()
, tak abyNgModelController
wiedział jak wyświetlić reprezentację modelu w naszym inpucie
Zadanie dla Ciebie:
- Dodaj dyrektywę
clearableInput
wykorzystującąngModel
, aby przywrócić two-way binding- Pytania?