AngularJS Directive – Scopes

Ik ben van plan om te praten over AngularJS Directives en verschillende soorten scopes die kunnen worden gebruikt. Er zijn 3 hoofdmanieren waarop scope aan de directive kan worden doorgegeven vanuit de aanroepende view (HTML):

  • Default Scope
  • Inherited Scope
  • Isolated Scope

En de isolated scope kan zelf ook zijn:

  • Oneway
  • Twoway
  • Method Reference

Default Scope

In dit type vloeit de scope van de buitenste view gewoon in de directive. Anders gezegd, de scope wordt als “referentie” aan de directive doorgegeven. Alle gegevens van het bereik zullen onmiddellijk beschikbaar zijn binnen de richtlijn om te consumeren. Op dezelfde manier zal elke verandering in de scope binnen de directive onmiddellijk worden doorgevoerd in de aanroepende view.

view en directive bound vis scope

Dit wordt bereikt door de scope te specificeren als

scope: false // false is the default value

in de directive definitie.

In het onderstaande voorbeeld wordt ‘name’ in de directive gevlogen en wordt elke wijziging die wordt aangebracht onmiddellijk naar buiten gereflecteerd. Omdat de scope true is gezet, krijgt de directive de scope als zijn aanroeper. Nu zal elke verandering die in de naam in de directive wordt aangebracht onmiddellijk worden gereflecteerd in de controller ‘MyController’.

var myApp = angular.module('myApp', );
myApp.controller('MyController', function($scope) {
$scope.name = "Jack";
});// usage: <div upper-case/></div>
myApp.directive('upperCase', function() {
return {
scope: false,
template: 'Name: <input ng-model="name"></input>'
}
});

Live fiddle is @ https://jsfiddle.net/madhanganesh/830rn1fm/

Inherited Scope

In dit type wordt een nieuwe scope geërfd van view scope. In Javascript worden objecten geërfd met behulp van prototypische overerving. Dit scenario is weergegeven in onderstaand diagram:

Dit wordt bereikt door de scope te specificeren als

scope: true

in de directive definitie.

In het onderstaande voorbeeld kun je proberen de naam te veranderen in de directive. Deze verandering zal niet naar buiten worden gereflecteerd vanwege de ‘geërfde’ scope. De waarde stroomt alleen naar binnen, maar elke verandering zal resulteren in een kopie voor de directive en zal niet naar buiten worden gereflecteerd.

In het live voorbeeld hieronder zie je dat de ‘name’ in de directive wordt gevlogen; maar verandering in de directive zal niet naar buiten worden gereflecteerd.

In het voorbeeld hieronder krijgt de directive scope de waarde true. Dit betekent dat er een scope wordt gemaakt voor de directive die “erft” van de scope van de controller. Volgens de prototypische overervingsregels van javascript, verwijst het afgeleide object (directive’s scope) naar dezelfde eigenschappen van het bovenliggende object (controller’s scope). Alle wijzigingen aan de controller zullen worden weerspiegeld in de richtlijn, totdat een wijziging wordt aangebracht in de “name” eigenschap in de richtlijn. Op dat moment wordt een nieuw object voor de directive gemaakt en zijn de wijzigingen ondoorzichtig voor elkaar.

var myApp = angular.module('myApp', );
myApp.controller('MyController', function($scope) {
$scope.name = "Jack";
});// usage: <div upper-case/></div>
myApp.directive('upperCase', function() {
return {
scope: true,
template: 'Name: <input ng-model="name"></input>'
}
});

Live fiddle is @ https://jsfiddle.net/madhanganesh/57sb6yg8/

Isolated Scope

In dit type scope-definitie krijgt de directive een onafhankelijke scope die geen gegevens ontvangt of terugstuurt naar de view die het bevat.

Dit wordt bereikt door de scope te specificeren als

scope: {}

in de directive-definitie.

In het onderstaande voorbeeld wordt isolated scope bereikt door een leeg object {} aan de directive mee te geven.

var myApp = angular.module('myApp', );
myApp.controller('MyController', function($scope) {
$scope.name = "Jack";
});// usage: <div upper-case/></div>
myApp.directive('upperCase', function() {
return {
scope: {},
template: 'Name: <input ng-model="name"></input>'
}
});

Live fiddle is @ https://jsfiddle.net/madhanganesh/7d37w08e/

Isolated scope is eigenlijk meer dan het volledig beperken van alle gegevens die in (en uit) de directive kunnen worden doorgegeven. Aan de ene kant van het spectrum kun je de data volledig beperken zoals in bovenstaand voorbeeld. Maar het is mogelijk om één of meer attributen aan een directief door te geven en ze vast te leggen als een scope voor de directief. De flexibiliteit zit in de manier waarop het doorgegeven attribuut in de directive wordt geïnterpreteerd. Het attribuut dat aan de directive wordt doorgegeven, kan op een van de volgende drie manieren worden geïnterpreteerd:

  • als een oneway die wordt geëvalueerd voordat hij aan de directive wordt doorgegeven
  • als een tweerichtings verwijzing naar een eigenschap in de aanroepende scope
  • als een verwijzing naar een methode in de aanroepende scope

Expression

De aanroeper van de directive kan expliciet een waarde doorgeven, zoals hieronder wordt getoond:

<div my-directive name='{{name}}' />
// an expression is passed to the directive

De manier waarop het in de directive wordt vastgelegd is:

scope: {
name: '@name'
}

@ symbool vertelt angular om het name attribuut als een expressie te beschouwen en deze te evalueren voordat de waarde aan de text eigenschap wordt toegekend. Omdat de expressie wordt geëvalueerd, is het een one-way binding en elke update gemaakt op de waarde binnen de richtlijn zal niet worden weerspiegeld buiten.

In het onderstaande voorbeeld, zie dat de naam eigenschap wordt doorgegeven aan de richtlijn. Dit is een expressie die wordt geëvalueerd en toegewezen aan het geisoleerde bereik van de richtlijn. Dit betekent dat de waarde “Jack” wordt geëvalueerd en toegewezen als tekst in de directive.

var myApp = angular.module('myApp', );
myApp.controller('MyController', function($scope) {
$scope.name = 'Jack';
});
// usage: <div my-directive name='{{name}}' />
myApp.directive('upperCase', function() {
return {
scope: {
name: '@name'
},
template: 'Name: <input ng-model="name"></input>'
}
});

Live fiddle is @ https://jsfiddle.net/madhanganesh/ybzcryt0/4/

Omdat naam een tekst in de directive is, zijn de wijzigingen lokaal in de directive en wordt niets gedeeld met de bovenliggende controller.

Tweezijdig (verwijzing naar eigenschap)

De aanroeper van de directive kan een verwijzing naar een eigenschap aan de directive doorgeven, zoals in:

<div my-directive name='data.name' />
// a property reference to the directive

De manier waarop dit in de directive wordt vastgelegd is:

scope: {
name: '=name'
}

= symbool vertelt angular om het name attribuut te beschouwen als een verwijzing naar een specifieke eigenschap van het aanroepende bereik. Dus de waarde wordt doorgegeven aan de richtlijn en elke verandering op de eigenschap wordt weerspiegeld buiten onmiddellijk.

In het voorbeeld hieronder, zie dat de naam eigenschap wordt doorgegeven aan de richtlijn. Dit is een verwijzing naar de eigenschap name in het bovenliggende bereik.

var myApp = angular.module('myApp', );
myApp.controller('MyController', function($scope) {
$scope.name = 'Jack';
});
myApp.directive('upperCase', function() {
return {
scope: {
name: '=name'
},
template: 'Name: <input ng-model="name"></input>'
}
});

Live fiddle is @ https://jsfiddle.net/madhanganesh/o74nvcj3/1/

Omdat name een verwijzing is naar de eigenschap in controller, worden wijzigingen aan beide zijden doorgevoerd in beide.

Referentie naar methode

De manier waarop het wordt doorgegeven vanuit de aanroepende view is:

<div my-directive nameFn="getName()" />
// a method reference is passed to the directive

De manier waarop het wordt vastgelegd in de directive is:

scope: {
nameFn: '& nameFn'
}

&symbool vertelt angular om het nameFn attribuut te beschouwen als een verwijzing naar specifieke methode van de aanroepende scope. Deze methode kan dan worden uitgevoerd vanuit de directive wanneer dat nodig is.

In het onderstaande voorbeeld kun je zien dat de nameFn eigenschap een methode is waarvan de referentie wordt doorgegeven binnen de directive. Deze functie wordt uitgevoerd vanuit de directive, maar geëvalueerd in de context van de aanroepende scope.

var myApp = angular.module('myApp', );
myApp.controller('MyController', function($scope) {
$scope.name = 'Jack';
$scope.getName = function() {
return $scope.name;
}
});
myApp.directive('upperCase', function() {
return {
scope: {
nameCb: '&name'
},
//template: 'Name: <input ng-model="nameFn()"></input>'
template: 'Name: {{textCb()}}'
}
});

Live fiddle is @ https://jsfiddle.net/madhanganesh/6w4msr5k/1/

Summary

Zoals je kunt zien is de directive scope nogal uitputtend, onderstaande samenvatting vat de mogelijkheden en hun betekenis.

  • Default : Directive krijgt dezelfde scope als zijn bevattende view
  • Inherited: Richtlijn krijgt een scope die geërfd is van de scope van de bevattende view
  • Geïsoleerd: Directive krijgt een bereik dat onafhankelijk is van het bevattende view

En binnen het Geïsoleerde bereik zijn er 3 mogelijkheden:

Oneway : Het directive attribuut wordt beschouwd als een expressie en wordt geëvalueerd voordat het wordt toegewezen aan een specifieke eigenschap van het Geïsoleerde bereik van de directive