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:

  1. Zakres: Fałsz (dyrektywa korzysta z zakresu nadrzędnego)
  2. Zakres: prawda (dyrektywa zyskuje nowy zakres)
  3. 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:

  1. „@” (Wiązanie tekstu / wiązanie jednostronne)
  2. "=" (Bezpośrednie wiązanie modelu / wiązanie dwustronne)
  3. „&” (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>


Modified text is an extract of the original Stack Overflow Documentation
Licencjonowany na podstawie CC BY-SA 3.0
Nie związany z Stack Overflow