AngularJS
solucja pętli
Szukaj…
Składnia
- $ scope. $ watch (watchExpression, callback, [deep Compare])
- $ scope. $ digest ()
- $ scope. $ apply ([exp])
dwukierunkowe wiązanie danych
Angular ma pod swoją maską trochę magii. umożliwia powiązanie DOM z rzeczywistymi zmiennymi js.
Angular używa pętli, zwanej „ pętlą podsumowania ”, która jest wywoływana po każdej zmianie zmiennej - wywołują oddzwanianie, które aktualizują DOM.
Na przykład ng-model
dyrektywa przywiązuje keyup
EventListener do tego wejścia:
<input ng-model="variable" />
Przy każdym uruchomieniu zdarzenia keyup
rozpoczyna się pętla podsumowania .
W pewnym momencie pętla podsumowania przechodzi przez wywołanie zwrotne, które aktualizuje zawartość tego zakresu:
<span>{{variable}}</span>
Podstawowy cykl życia tego przykładu podsumowuje (bardzo Schematycznie), w jaki sposób działa kąt:
- Skanowanie kątowe HTML
- Dyrektywa
ng-model
tworzy nasłuchiwaniekeyup
podczas wprowadzania -
expression
wewnątrz zakresu dodaje wywołanie zwrotne do cyklu trawienia
- Dyrektywa
- Użytkownik wchodzi w interakcje z danymi wejściowymi
- nasłuchiwanie
keyup
rozpoczyna cykl podsumowania - cykl skrótu wywołuje wywołanie zwrotne
- Oddzwanianie aktualizuje zawartość zakresu
- nasłuchiwanie
$ skrót i $ zegarek
Wdrożenie dwukierunkowego wiązania danych, aby osiągnąć wynik z poprzedniego przykładu, można wykonać za pomocą dwóch podstawowych funkcji:
- $ digest jest wywoływany po interakcji użytkownika (wiązanie zmiennej DOM =>)
- $ watch ustawia wywołanie zwrotne, które będzie wywoływane po zmianach zmiennych (powiązanie zmiennej => DOM)
Uwaga: to przykład, a nie rzeczywisty kod kątowy
<input id="input"/>
<span id="span"></span>
Dwie potrzebne nam funkcje:
var $watches = [];
function $digest(){
$watches.forEach(function($w){
var val = $w.val();
if($w.prevVal !== val){
$w.callback(val, $w.prevVal);
$w.prevVal = val;
}
})
}
function $watch(val, callback){
$watches.push({val:val, callback:callback, prevVal: val() })
}
Teraz moglibyśmy teraz użyć tych funkcji, aby podłączyć zmienną do DOM (angular ma wbudowane dyrektywy, które zrobią to za Ciebie):
var realVar;
//this is usually done by ng-model directive
input1.addEventListener('keyup',function(e){
realVar=e.target.value;
$digest()
}, true);
//this is usually done with {{expressions}} or ng-bind directive
$watch(function(){return realVar},function(val){
span1.innerHTML = val;
});
Oczywiście rzeczywiste implementacje są bardziej złożone i obsługują parametry, takie jak element, z którym należy się powiązać i jaką zmienną użyć
Działający przykład można znaleźć tutaj: https://jsfiddle.net/azofxd4j/
drzewo $ scope
Poprzedni przykład jest wystarczająco dobry, gdy musimy powiązać pojedynczy element HTML z jedną zmienną.
W rzeczywistości - musimy powiązać wiele elementów z wieloma zmiennymi:
<span ng-repeat="number in [1,2,3,4,5]">{{number}}</span>
To ng-repeat
wiąże 5 elementów z 5 zmiennymi zwanymi number
, z inną wartością dla każdego z nich!
Sposób, w jaki kąt osiąga to zachowanie, polega na zastosowaniu osobnego kontekstu dla każdego elementu, który potrzebuje osobnych zmiennych. Ten kontekst nazywa się zakresem.
Każdy zakres zawiera właściwości, które są zmiennymi powiązanymi z DOM, a funkcje $digest
i $watch
są zaimplementowane jako metody zakresu.
DOM jest drzewem, a zmiennych należy używać na różnych poziomach drzewa:
<div>
<input ng-model="person.name" />
<span ng-repeat="number in [1,2,3,4,5]">{{number}} {{person.name}}</span>
</div>
Ale jak widzieliśmy, kontekst (lub zakres) zmiennych wewnątrz ng-repeat
jest inny niż kontekst powyżej. Aby rozwiązać ten problem - kątowe implementuje zakresy jako drzewo.
Każdy zakres ma tablicę elementów podrzędnych, a wywołanie jego metody $digest
uruchomi wszystkie metody $digest
dziecka.
W ten sposób - po zmianie danych wejściowych - wywoływany jest $digest
dla zakresu div, który następnie uruchamia $digest
dla swoich 5 elementów potomnych - co zaktualizuje jego zawartość.
Prosta implementacja zakresu może wyglądać następująco:
function $scope(){
this.$children = [];
this.$watches = [];
}
$scope.prototype.$digest = function(){
this.$watches.forEach(function($w){
var val = $w.val();
if($w.prevVal !== val){
$w.callback(val, $w.prevVal);
$w.prevVal = val;
}
});
this.$children.forEach(function(c){
c.$digest();
});
}
$scope.prototype.$watch = function(val, callback){
this.$watches.push({val:val, callback:callback, prevVal: val() })
}
Uwaga: to przykład, a nie rzeczywisty kod kątowy