AngularJS
Lunety kątowe
Szukaj…
Uwagi
Angular używa drzewa zakresów do powiązania logiki (z kontrolerów, dyrektyw itp.) Z widokiem i jest głównym mechanizmem kryjącym się za wykrywaniem zmian w AngularJS. Bardziej szczegółowe odniesienie do zakresów można znaleźć na docs.quarejs.org
Katalog główny drzewa jest dostępny, jak za pośrednictwem usługi iniekcji $ rootScope . Wszystkie potomne zakresy $ dziedziczą metody i właściwości ich nadrzędnego zakresu $, umożliwiając dzieciom dostęp do metod bez korzystania z usług Angular.
Podstawowy przykład dziedziczenia zakresu $
angular.module('app', [])
.controller('myController', ['$scope', function($scope){
$scope.person = { name: 'John Doe' };
}]);
<div ng-app="app" ng-conroller="myController">
<input ng-model="person.name" />
<div ng-repeat="number in [0,1,2,3]">
{{person.name}} {{number}}
</div>
</div>
W tym przykładzie dyrektywa ng-repeat tworzy nowy zakres dla każdego z nowo utworzonych elementów potomnych.
Te utworzone zakresy są potomkami swojego nadrzędnego zakresu (w tym przypadku zakresu utworzonego przez myController) i dlatego dziedziczą wszystkie jego proporcje, takie jak osoba.
Unikaj dziedziczenia pierwotnych wartości
W javascript, przypisanie nieprymitywnej wartości (takiej jak Object, Array, Function i wiele innych) zachowuje odniesienie (adres w pamięci) do przypisanej wartości.
Przypisanie wartości pierwotnej (Ciąg, Liczba, Wartość logiczna lub Symbol) do dwóch różnych zmiennych i zmiana jednej nie zmieni obu:
var x = 5;
var y = x;
y = 6;
console.log(y === x, x, y); //false, 5, 6
Ale z non-prymitywnego wartości, ponieważ obie zmienne są po prostu utrzymanie odniesienia do tego samego obiektu, zmieniając jedną zmienną zmieni drugiej:
var x = { name : 'John Doe' };
var y = x;
y.name = 'Jhon';
console.log(x.name === y.name, x.name, y.name); //true, John, John
Angular, gdy tworzony jest zakres, zostaje mu przypisane wszystkie właściwości jego rodzica. Jednak późniejsze zmiany właściwości wpłyną na zasięg nadrzędny tylko wtedy, gdy jest to wartość nieprywatna:
angular.module('app', [])
.controller('myController', ['$scope', function($scope){
$scope.person = { name: 'John Doe' }; //non-primitive
$scope.name = 'Jhon Doe'; //primitive
}])
.controller('myController1', ['$scope', function($scope){}]);
<div ng-app="app" ng-controller="myController">
binding to input works: {{person.name}}<br/>
binding to input does not work: {{name}}<br/>
<div ng-controller="myController1">
<input ng-model="person.name" />
<input ng-model="name" />
</div>
</div>
Pamiętaj: w Angular zakresy można tworzyć na wiele sposobów (takie jak dyrektywy wbudowane lub niestandardowe lub funkcja $scope.$new()
), a śledzenie drzewa zakresu prawdopodobnie nie jest możliwe.
Używanie tylko nieprymitywnych wartości jako właściwości zakresu zapewni bezpieczeństwo (chyba że potrzebujesz właściwości, aby nie dziedziczyć, lub innych przypadków, w których masz świadomość dziedziczenia zakresu).
Funkcja dostępna w całej aplikacji
Bądź ostrożny, takie podejście może być uważane za zły projekt dla aplikacji kątowych, ponieważ wymaga od programistów zapamiętywania obu miejsc, w których funkcje są umieszczone w drzewie zasięgu, i bycia świadomym dziedziczenia zakresu. W wielu przypadkach preferowane byłoby wstrzyknięcie usługi ( praktyka kątowa - przy użyciu dziedziczenia zakresu vs wstrzyknięcia) .
Ten przykład pokazuje tylko, w jaki sposób można wykorzystać dziedziczenie zakresu dla naszych potrzeb i jak możesz z niego skorzystać, a nie najlepsze praktyki projektowania całej aplikacji.
W niektórych przypadkach moglibyśmy skorzystać z dziedziczenia zakresu i ustawić funkcję jako właściwość rootScope. W ten sposób - wszystkie zakresy w aplikacji (z wyjątkiem zakresów izolowanych) odziedziczą tę funkcję i można ją wywołać z dowolnego miejsca w aplikacji.
angular.module('app', [])
.run(['$rootScope', function($rootScope){
var messages = []
$rootScope.addMessage = function(msg){
messages.push(msg);
}
}]);
<div ng-app="app">
<a ng-click="addMessage('hello world!')">it could be accsessed from here</a>
<div ng-include="inner.html"></div>
</div>
inner.html:
<div>
<button ng-click="addMessage('page')">and from here to!</button>
</div>
Tworzenie niestandardowych zdarzeń $ scope
Podobnie jak normalne elementy HTML, zakresy $ mogą mieć własne zdarzenia. Zdarzenia o zasięgu $ można subskrybować w następujący sposób:
$scope.$on('my-event', function(event, args) {
console.log(args); // { custom: 'data' }
});
Jeśli potrzebujesz wyrejestrować detektor zdarzeń, funkcja $ on zwróci funkcję unbinding. Aby kontynuować z powyższym przykładem:
var unregisterMyEvent = $scope.$on('my-event', function(event, args) {
console.log(args); // { custom: 'data' }
unregisterMyEvent();
});
Istnieją dwa sposoby wyzwalania własnego niestandardowego zdarzenia $ scope $ broadcast i $ emit . Aby powiadomić rodziców (rodziców) o zakresie określonego zdarzenia, użyj $ emit
$scope.$emit('my-event', { custom: 'data' });
Powyższy przykład wyzwoli wszystkie detektory zdarzeń dla my-event
w zakresie nadrzędnym i będzie kontynuował tworzenie drzewa zasięgu do $ rootScope, chyba że detektor stopPropagation
w zdarzeniu. Tylko zdarzenia wywołane przez $ stopPropagation
mogą wywoływać stopPropagation
Odwrotnością $ emit jest $ broadcast , który wyzwoli wszystkie detektory zdarzeń we wszystkich zakresach potomnych w drzewie zasięgu, które są potomkami zakresu, który wywołał $ broadcast .
$scope.$broadcast('my-event', { custom: 'data' });
Zdarzenia wywołane przez $ broadcast nie mogą być anulowane.
Korzystanie z funkcji $ scope
Chociaż deklarowanie funkcji w $ rootscope ma swoje zalety, możemy również zadeklarować funkcję $ scope dowolną część kodu, która jest wstrzykiwana przez usługę $ scope. Na przykład kontroler.
Kontroler
myApp.controller('myController', ['$scope', function($scope){
$scope.myFunction = function () {
alert("You are in myFunction!");
};
}]);
Teraz możesz wywołać swoją funkcję ze sterownika za pomocą:
$scope.myfunction();
Lub przez HTML, który jest pod tym konkretnym kontrolerem:
<div ng-controller="myController">
<button ng-click="myFunction()"> Click me! </button>
</div>
Dyrektywa
Dyrektywa kątowa to kolejne miejsce, w którym możesz używać swojego lunety:
myApp.directive('triggerFunction', function() {
return {
scope: {
triggerFunction: '&'
},
link: function(scope, element) {
element.bind('mouseover', function() {
scope.triggerFunction();
});
}
};
});
A w kodzie HTML pod tym samym kontrolerem:
<div ng-controller="myController">
<button trigger-function="myFunction()"> Hover over me! </button>
</div>
Oczywiście możesz używać ngMouseover do tej samej rzeczy, ale specjalną cechą dyrektyw jest to, że możesz dostosować je tak, jak chcesz. A teraz wiesz, jak korzystać z funkcji $ scope w nich, bądź kreatywny!
Jak możesz ograniczyć zakres dyrektywy i dlaczego to zrobiłbyś?
Zakres jest używany jako „klej”, którego używamy do komunikacji między kontrolerem nadrzędnym, dyrektywą i szablonem dyrektywy. Po każdym uruchomieniu aplikacji AngularJS tworzony jest obiekt rootScope. Każdy zakres utworzony przez kontrolery, dyrektywy i usługi jest prototypowo dziedziczony z rootScope.
Tak, możemy ograniczyć zakres dyrektywy. Możemy to zrobić, tworząc izolowany zakres dla dyrektywy.
Istnieją 3 rodzaje zakresów dyrektyw:
- Zakres: Fałsz (dyrektywa korzysta z zakresu nadrzędnego)
- Zakres: prawda (dyrektywa zyskuje nowy zakres)
- Zakres: {} (dyrektywa otrzymuje nowy izolowany zakres)
Dyrektywy z nowym izolowanym zakresem: Kiedy tworzymy nowy izolowany zakres, nie będzie on dziedziczony z zakresu nadrzędnego. Ten nowy zakres nosi nazwę zakresu izolowanego, ponieważ jest całkowicie odłączony od zakresu nadrzędnego. Dlaczego? czy powinniśmy używać izolowanego zakresu: powinniśmy używać izolowanego zakresu, gdy chcemy utworzyć niestandardową dyrektywę, ponieważ upewni się, że nasza dyrektywa jest ogólna i umieszczona w dowolnym miejscu w aplikacji. Zakres nadrzędny nie będzie kolidował z zakresem dyrektywy.
Przykład izolowanego zakresu:
var app = angular.module("test",[]);
app.controller("Ctrl1",function($scope){
$scope.name = "Prateek";
$scope.reverseName = function(){
$scope.name = $scope.name.split('').reverse().join('');
};
});
app.directive("myDirective", function(){
return {
restrict: "EA",
scope: {},
template: "<div>Your name is : {{name}}</div>"+
"Change your name : <input type='text' ng-model='name'/>"
};
});
Istnieją 3 rodzaje przedrostków, które AngularJS zapewnia dla izolowanego zakresu, są to:
- „@” (Wiązanie tekstu / wiązanie jednostronne)
- "=" (Bezpośrednie wiązanie modelu / wiązanie dwustronne)
- „&” (Wiązanie behawioralne / wiązanie metod)
Wszystkie te przedrostki otrzymują dane z atrybutów elementu dyrektywy, takich jak:
<div my-directive
class="directive"
name="{{name}}"
reverse="reverseName()"
color="color" >
</div>