Sök…


Syntax

  • $ omfattning. $ klocka (klockuttryck, återuppringning, [djup jämförelse])
  • $ Omfattning. $ Smälta ()
  • $ Omfattning. $ Gäller ([exp])

tvåvägsdata bindande

Angular har lite magi under huven. det gör det möjligt att binda DOM till verkliga js-variabler.

Angular använder en slinga, kallad " digest loop ", som kallas efter varje ändring av en variabel - samtalsuppringningar som uppdaterar DOM.

Till exempel keyup ng-model keyup en keyup händelseListener till denna ingång:

<input ng-model="variable" />

Varje gång keyup bränderna händelse det smälta sling startar.

Vid något tillfälle, det smälta sling itererar över en callback som uppdaterar innehållet i denna spännvidd:

<span>{{variable}}</span>

Den grundläggande livscykeln i detta exempel sammanfattar (mycket schematiskt) hur vinkel fungerar ::

  1. Vinkelskannar html
    • ng-model keyup skapar en keyup på input
    • expression inuti spännvidden lägger till ett återuppringning till digerecykeln
  2. Användaren interagerar med input
    • keyup lyssnaren börjar matningscykeln
    • digest-cykel ringer återuppringningen
    • Uppringningens uppdatering spänner innehåll

$ digest och $ watch

Implementering av tvåvägs-databindning, för att uppnå resultatet från föregående exempel, kan göras med två kärnfunktioner:

  • $ digest kallas efter en användarinteraktion (bindande DOM => variabel)
  • $ watch ställer in en återuppringning som ska kallas efter variabla förändringar (bindningsvariabel => DOM)

Obs! Detta exempel är en demonstration, inte den faktiska vinkelkoden


<input id="input"/>
<span id="span"></span>

De två funktionerna vi behöver:

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() })
}

Nu kan vi nu använda dessa funktioner för att ansluta en variabel till DOM (vinkel kommer med inbyggda direktiv som kommer att göra detta åt dig):

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;
});

Självklart är de verkliga implementeringarna mer komplexa, och stödsparametrar som vilket element du vill binda till och vilken variabel som ska användas

Ett löpande exempel kan hittas här: https://jsfiddle.net/azofxd4j/

$ scope-trädet

Det föregående exemplet är tillräckligt bra när vi måste binda ett enda html-element till en enda variabel.

I verkligheten - vi måste binda många element till många variabler:

<span ng-repeat="number in [1,2,3,4,5]">{{number}}</span>

Denna ng-repeat binder 5 element till 5 variabler som kallas number , med ett annat värde för var och en av dem!


Det sätt som vinkeln uppnår detta beteende använder ett separat sammanhang för varje element som behöver separata variabler. Detta sammanhang kallas en omfattning.

Varje omfattning innehåller egenskaper, som är variablerna bundna till DOM, och funktionerna $digest och $watch implementeras som metoder för omfattningen.

DOM är ett träd, och variabler måste användas i olika nivåer av trädet:

<div>
    <input ng-model="person.name" />
    <span ng-repeat="number in [1,2,3,4,5]">{{number}} {{person.name}}</span>
</div>

Men som vi såg är sammanhanget (eller omfattningen) av variabler i ng-repeat annorlunda än sammanhanget ovanför. För att lösa detta - vinklar implementerar omfång som ett träd.

Varje räckvidd har en mängd barn, och att kalla sin $digest metod kommer att köra alla sina barns $digest metod.

På det här sättet - efter att ha ändrat ingången - kallas $digest för div: s omfattning, som sedan kör $digest för sina 5 barn - vilket kommer att uppdatera dess innehåll.


En enkel implementering av en omfattning kan se ut så här:

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() })
}

Obs! Detta exempel är en demonstration, inte den faktiska vinkelkoden



Modified text is an extract of the original Stack Overflow Documentation
Licensierat under CC BY-SA 3.0
Inte anslutet till Stack Overflow