Jaka jest różnica między „@” a „=” w zakresie dyrektywy w AngularJS?

1067

Przeczytałem uważnie dokumentację AngularJS na ten temat, a następnie majstrowałem przy dyrektywie. Oto skrzypce .

A oto kilka istotnych fragmentów:

  • Z HTML :

    <pane bi-title="title" title="{{title}}">{{text}}</pane>
  • Z dyrektywy dotyczącej okien:

    scope: { biTitle: '=', title: '@', bar: '=' },

Jest kilka rzeczy, których nie rozumiem:

  • Dlaczego muszę korzystać "{{title}}"z '@'i "title"ze '='?
  • Czy mogę również uzyskać bezpośredni dostęp do zakresu nadrzędnego, bez ozdabiania mojego elementu atrybutem?
  • Dokumentacja mówi „Często pożądane jest przekazywanie danych z izolowanego zakresu przez wyrażenie i do zakresu nadrzędnego” , ale wydaje się, że działa to dobrze również w przypadku wiązania dwukierunkowego. Dlaczego droga ekspresowa byłaby lepsza?

Znalazłem też inne skrzypce, które pokazują rozwiązanie wyrażeń: http://jsfiddle.net/maxisam/QrCXh/

iwein
źródło
18
Uczciwy punkt. Ważna jest umiejętność badania i znajdowania odpowiedzi.
Jonathan
1
Mówiąc prosto, =w dyrektywie wyodrębniono zakres, aby umożliwić dwukierunkowe wiązanie i @nie aktualizuje modelu, jedynie aktualizuje wartości zakresu dyrektywy.
STEEL,
@ iwein dlaczego Twój kod skrzypiec na jsfiddle.net/maxisam/QrCXh nie działa z googleapi - ajax.googleapis.com/ajax/libs/angularjs/1.4.8/angular.min.js ? Twój kod działa tylko wtedy, gdy używam twojego cdn - code.angularjs.org/1.0.1/angular-1.0.1.js
MukulSharma
Widzę wiele dobrych odpowiedzi poniżej, ale czy ktoś może wskazać oficjalną dokumentację kątową, która odpowiada na to pytanie?
John Henckel,

Odpowiedzi:

1151

Dlaczego muszę używać „{{title}}” z „ @ ” i „title” z „ = ”?

@ wiąże właściwość zasięgu lokalnego / dyrektywy z oszacowaną wartością atrybutu DOM . Jeśli używasz title=title1lub title="title1", wartość atrybutu DOM „tytuł” ​​jest po prostu łańcuchem title1. Jeśli użyjesz title="{{title}}", wartość atrybutu DOM „tytuł” ​​jest wartością interpolowaną {{title}}, a zatem ciąg będzie tym, czym jest obecnie ustawiona dowolna właściwość zakresu nadrzędnego „tytuł”. Ponieważ wartości atrybutów są zawsze ciągami, podczas korzystania z @ zawsze otrzymasz wartość ciągu dla tej właściwości w zakresie dyrektywy .

= wiąże właściwość zakresu lokalnego / dyrektywy z właściwością zakresu nadrzędnego . Tak więc z = używasz nazwy właściwości modelu nadrzędnego / zakresu jako wartości atrybutu DOM. Nie możesz używać {{}}s z = .

Za pomocą @ możesz robić takie rzeczy, jak title="{{title}} and then some"- {{tytuł}} jest interpolowany, a następnie ciąg „i niektóre z nich” jest z nim łączony. Ostateczny skonkatenowany ciąg jest tym, co otrzymuje właściwość zasięgu lokalnego / dyrektywy. (Nie możesz tego zrobić za pomocą = , tylko @ .)

Przy @ musisz użyć, attr.$observe('title', function(value) { ... })jeśli chcesz użyć wartości w funkcji linkowania. Np. if(scope.title == "...")Nie będzie działać tak, jak się spodziewasz. Pamiętaj, że oznacza to, że możesz uzyskać dostęp do tego atrybutu tylko asynchronicznie . Nie musisz używać $ observ (), jeśli używasz tylko wartości w szablonie. Np template: '<div>{{title}}</div>'.

Dzięki = nie musisz używać $ observ.

Czy mogę również uzyskać bezpośredni dostęp do zakresu nadrzędnego, bez ozdabiania mojego elementu atrybutem?

Tak, ale tylko jeśli nie używasz zakresu izolowanego. Usuń ten wiersz ze swojej dyrektywy

scope: { ... }

a wtedy twoja dyrektywa nie stworzy nowego zakresu. Użyje zakresu nadrzędnego. Następnie można uzyskać bezpośredni dostęp do wszystkich właściwości zakresu nadrzędnego.

Dokumentacja mówi: „Często pożądane jest przekazywanie danych z izolowanego zakresu przez wyrażenie i do zakresu nadrzędnego”, ale wydaje się, że działa to dobrze również w przypadku wiązania dwukierunkowego. Dlaczego droga ekspresowa byłaby lepsza?

Tak, wiązanie dwukierunkowe umożliwia współużytkowanie danych przez zakres lokalny / dyrektywny i nadrzędny. „Powiązanie wyrażeń” umożliwia dyrektywie wywołanie wyrażenia (lub funkcji) zdefiniowanej przez atrybut DOM - a także można przekazać dane jako argumenty do wyrażenia lub funkcji. Jeśli więc nie musisz współdzielić danych z rodzicem - chcesz tylko wywołać funkcję zdefiniowaną w zakresie nadrzędnym - możesz użyć składni & .

Zobacz też

Mark Rajcok
źródło
1
To jest naprawdę dziwne zachowanie, szczególnie gdy nie używa się interpolacji i po prostu próbuje przekazać ciąg znaków. Najwyraźniej żądanie ściągnięcia zostało rzeczywiście włączone do kompilacji programistycznych i znajduje się w kompilacjach RC 1.1.5 i 1.2.0. Dobrze, jeśli naprawią to bardzo nieintuicyjne zachowanie!
Ibrahim,
50
Pisanie „@” lub „=” jest o wiele jaśniejsze niż pisanie „eval-dom” lub „parent-scope” lub innego tekstu czytelnego dla człowieka. Dobra decyzja projektowa.
Den
13
@(„at”) kopiuje wartość „ATtribute”. =(„równa się”) jest równoznaczne z twierdzeniem, że klucz jest równy wyrażeniu. Tak przynajmniej utrzymuję ich w cieśninie.
Matt DeKrey
1
Czy jesteś pewien, że = dotyczy tylko właściwości o zakresie nadrzędnym? Wydaje się, że każde wyrażenie działa - nie tylko właściwości nadrzędne.
Jonathan Aquino
4
@JonathanAquino, tak, to działa, ale @ byłoby bardziej odpowiednie - z foo="{{1+1}}"- ponieważ nie potrzebujemy tutaj dwukierunkowego wiązania danych. W powyższym komentarzu starałem się podkreślić, że powinniśmy używać = tylko wtedy, gdy dyrektywa wymaga dwukierunkowego powiązania danych. Użyj @ lub w inny sposób.
Mark Rajcok
542

Istnieje wiele wspaniałych odpowiedzi tutaj, ale chciałbym zaoferować moją perspektywę na różnicach pomiędzy @, =i &wiązania, które okazały się przydatne dla mnie.

Wszystkie trzy powiązania są sposobami przekazywania danych z zakresu nadrzędnego do izolowanego zakresu dyrektywy przez atrybuty elementu:

  1. @ wiązanie służy do przekazywania ciągów znaków. Te łańcuchy obsługują {{}}wyrażenia dla interpolowanych wartości. Na przykład: . Interpolowane wyrażenie jest oceniane względem zakresu nadrzędnego dyrektywy.

  2. = wiązanie służy do wiązania modelu dwukierunkowego. Model w zakresie nadrzędnym jest powiązany z modelem w odizolowanym zakresie dyrektywy. Zmiany w jednym modelu wpływają na drugi i odwrotnie.

  3. & bindowanie służy do przekazania metody do zakresu dyrektywy, aby można ją było wywołać w ramach dyrektywy. Metoda jest wstępnie związana z nadrzędnym zakresem dyrektywy i obsługuje argumenty. Na przykład, jeśli metoda ma hello (name) w zakresie nadrzędnym, to aby wykonać metodę z wnętrza dyrektywy, musisz wywołać $ scope.hello ({name: 'world'})

Uważam, że łatwiej jest zapamiętać te różnice, odwołując się do powiązań zakresu przez krótszy opis:

  • @ Wiązanie ciągu atrybutu
  • = Wiązanie modelu dwukierunkowego
  • & Powiązanie metody wywołania zwrotnego

Symbole również wyjaśniają, co zmienna zakresu reprezentuje wewnątrz implementacji twojej dyrektywy:

  • @ strunowy
  • = Model
  • & metoda

W kolejności przydatności (w każdym razie dla mnie):

  1. =
  2. @
  3. I
piksele
źródło
13
W rzeczywistości "&"obsługuje argumenty (a raczej miejscowe) formularza:, callback({foo: "some value"})które można by następnie wykorzystać <my-dir callback="doSomething(foo)">. W przeciwnym razie dobra odpowiedź
New Dev
11
Należy przyjąć odpowiedź. Oto zwięzły artykuł z tymi samymi informacjami, ale z dodanymi przykładami kodu: umur.io/…
Kevin
4
NIE jest to „Powiązanie metody wywołania zwrotnego”, jest to wiązanie wyrażenia kątowego. Szczególnym, ale nie jedynym przykładem jest wyrażenie callback(argument). Co wciąż nie jest tym samym co on callbacksam.
Dmitri Zaitsev,
14
Chociaż podobało mi się to, jak ostateczna była odpowiedź na wyższą pozycję, zauważyłem, że ma ona bardziej użyteczny wpływ i po przeczytaniu tej odpowiedzi zrozumiałem znacznie więcej.
rbnzdave
1
Zgadzam się z powyższym komentarzem, ta odpowiedź jest bardziej jasna, ostateczna i użyteczna dla pytania. Wyjaśnia z wystarczającą ilością szczegółów, że możesz przejść i skorzystać z informacji.
user3125823,
64

W =sposób dwukierunkowy wiążące, a więc odniesienia do zmiennej do zakresu macierzystego. Oznacza to, że jeśli zmienisz zmienną w dyrektywie, zostanie ona również zmieniona w zakresie nadrzędnym.

@ oznacza, że ​​zmienna zostanie skopiowana (sklonowana) do dyrektywy.

O ile wiem, też <pane bi-title="{{title}}" title="{{title}}">{{text}}</pane>powinien działać. bi-titleotrzyma wartość zmiennej zakresu nadrzędnego, którą można zmienić w dyrektywie.

Jeśli musisz zmienić kilka zmiennych w zakresie nadrzędnym, możesz wykonać funkcję w zakresie nadrzędnym z poziomu dyrektywy (lub przekazać dane za pośrednictwem usługi).

asgoth
źródło
1
Tak, tę część dostaję, patrz skrzypce w pytaniu. Ale co z częściami, które są niejasne?
iwein 27.12.12
4
Chodzi o to, że {{}} nie działa z =. = nie jest obliczany, ale ciąg jest traktowany jako nazwa właściwości, jak jest. Dziękuję za odpowiedź!
iwein 30.12.12
1
Nie sądzę, że = dotyczy tylko zmiennych w zakresie nadrzędnym. Działa z dowolnym wyrażeniem (np. 1 + 1).
Jonathan Aquino
1
@JonathanAquino masz rację, że ocenia wyrażenia. imho to jest naprawdę dziwne i nie użyłbym tego w ten sposób. To takie sprytne sztuczki, które sprawiają, że zakresy dyrektywy są dla mnie tak trudne do zrozumienia.
iwein
1
Czy jestem jedynym, który uważa, że ​​ta odpowiedź jest błędna! „=” oznacza kątowe oczekiwanie na wyrażenie javascript i wykona mapowanie dwukierunkowe, jeśli zostanie przekazana zmienna zasięgu. Podczas gdy @ oznacza kątowe oczekuj String i to wszystko. W rzeczywistości prawdą jest, że jeśli użyjesz @ w połączeniu z {{}}, sklonujesz wartość zmiennej. Ale to nie jest definicja @!
Luc DUZAN
39

Jeśli chcesz zobaczyć więcej, jak to działa na przykładzie na żywo. http://jsfiddle.net/juanmendez/k6chmnch/

var app = angular.module('app', []);
app.controller("myController", function ($scope) {
    $scope.title = "binding";
});
app.directive("jmFind", function () {
    return {
        replace: true,
        restrict: 'C',
        transclude: true,
        scope: {
            title1: "=",
            title2: "@"
        },
        template: "<div><p>{{title1}} {{title2}}</p></div>"
    };
});
Juan Mendez
źródło
2
Istnieje kilka przykładów powiązanych w pytaniu i najważniejszej odpowiedzi. Co to dodaje?
iwein
10
@ iwein, dodaje przejrzystości. Gdybym mógł zrozumieć i przyswoić w pełni funkcjonalne przykłady, nie potrzebowałbym tej witryny.
Tony Ennis,
3
juan, może naprawisz swoje literówki? „transclude” jest błędnie napisane. jeszcze lepiej, usuń go (i wszystko inne, na przykład „zamień”), co nie przyczynia się bezpośrednio do problemu, dzięki czemu Twoje rozwiązanie jest jeszcze prostsze i jaśniejsze. +1 na przykład.
Tony Ennis,
dziękuję @AnikISlamAbhi za edycję. Chciałbym przyczynić się więcej i cieszę się, że moje próbki były pomocne. To jest główny cel.
Juan Mendez,
Niekompletny przykład. W swojej demonstracji zmieniasz tylko wartość dwukierunkową. Nie próbujesz nawet zmieniać wartości, która ma izolowany zakres. Tak więc nie wykazał on poprawnie, jak działa zakres w dyrektywach.
Sudarshan_SMD
38

@ dostać jako ciąg

  • Nie tworzy to żadnych powiązań. Po prostu dostajesz słowo, które przekazałeś jako ciąg

= 2-kierunkowe wiązanie

  • zmiany wprowadzone przez administratora zostaną odzwierciedlone w odnośniku będącym w posiadaniu dyrektywy i odwrotnie

&Zachowuje się to nieco inaczej, ponieważ zakres otrzymuje funkcję, która zwraca przekazany obiekt . Zakładam, że było to konieczne, aby działało. Skrzypce powinny to wyjaśnić.

  • Po wywołaniu tej funkcji pobierającej wynikowy obiekt zachowuje się w następujący sposób:
    • jeśli funkcja została przekazana: wtedy funkcja jest wykonywana w zamknięciu rodzica (kontrolera) po wywołaniu
    • jeśli przekazano niefunkcję : po prostu pobierz lokalną kopię obiektu, który nie ma powiązań


To skrzypce powinno pokazać, jak działają . Zwróć szczególną uwagę na funkcje lunety get...w nazwie, aby, mam nadzieję, lepiej zrozumieć, o co mi chodzi&

geg
źródło
36

Istnieją trzy sposoby dodania zakresu w dyrektywie:

  1. Zakres nadrzędny : jest to domyślne dziedziczenie zakresu.

Dyrektywa i jej nadrzędny (kontroler / dyrektywa, w której się znajduje) zakres jest taki sam. Zatem wszelkie zmiany w zmiennych zasięgu wewnątrz dyrektywy są odzwierciedlane również w kontrolerze nadrzędnym. Nie musisz tego określać, ponieważ jest to ustawienie domyślne.

  1. Zasięg podrzędny : dyrektywa tworzy zasięg podrzędny, który dziedziczy z zasięgu nadrzędnego, jeśli zmienna zakresu dyrektywy zostanie określona jako prawdziwa.

Tutaj, jeśli zmienisz zmienne zasięgu w dyrektywie, nie będzie to odzwierciedlać zakresu nadrzędnego, ale jeśli zmienisz właściwość zmiennej zasięgu, co zostanie odzwierciedlone w zakresie nadrzędnym, tak jak faktycznie zmodyfikowałeś zmienną zakresu nadrzędnego .

Przykład,

app.directive("myDirective", function(){

    return {
        restrict: "EA",
        scope: true,
        link: function(element, scope, attrs){
            scope.somvar = "new value"; //doesnot reflect in the parent scope
            scope.someObj.someProp = "new value"; //reflects as someObj is of parent, we modified that but did not override.
        }
    };
});
  1. Zakres izolowany : jest używany, gdy chcesz utworzyć zakres, który nie dziedziczy z zakresu kontrolera.

Dzieje się tak, gdy tworzysz wtyczki, ponieważ czyni to dyrektywę ogólną, ponieważ można ją umieścić w dowolnym HTML i nie ma wpływu na jej zakres nadrzędny.

Teraz, jeśli nie chcesz żadnej interakcji z zakresem nadrzędnym, możesz po prostu określić zakres jako pusty obiekt. lubić,

scope: {} //this does not interact with the parent scope in any way

Przeważnie tak nie jest, ponieważ potrzebujemy interakcji z zakresem nadrzędnym, dlatego chcemy, aby niektóre wartości / zmiany zostały przekazane. Z tego powodu używamy:

1. "@"   (  Text binding / one-way binding )
2. "="   ( Direct model binding / two-way binding )
3. "&"   ( Behaviour binding / Method binding  )

@ oznacza, że ​​zmiany z zakresu kontrolera zostaną odzwierciedlone w zakresie dyrektywy, ale jeśli zmodyfikujesz wartość w zakresie dyrektywy, zmienna zakresu kontrolera nie zostanie zmieniona.

@ zawsze oczekuje, że odwzorowany atrybut będzie wyrażeniem. To jest bardzo ważne; ponieważ aby prefiks „@” działał, musimy owinąć wartość atrybutu wewnątrz {{}}.

= jest dwukierunkowy, więc zmiana zmiennej w zakresie dyrektywy również wpływa na zmienną zakresu kontrolera

& służy do powiązania metody zakresu kontrolera, aby w razie potrzeby można ją było wywołać z dyrektywy

Zaletą jest to, że nazwa zmiennej nie musi być taka sama w zakresie kontrolera i zakresie dyrektywy.

Przykład, zakres dyrektywy ma zmienną „dirVar”, która synchronizuje się ze zmienną „contVar” zakresu kontrolera. Daje to dużą moc i uogólnienie dyrektywy, ponieważ jeden kontroler może synchronizować ze zmienną v1, podczas gdy inny kontroler używający tej samej dyrektywy może poprosić dirVar o synchronizację ze zmienną v2.

Poniżej znajduje się przykład użycia:

Dyrektywą i kontrolerem są:

 var app = angular.module("app", []);
 app.controller("MainCtrl", function( $scope ){
    $scope.name = "Harry";
    $scope.color = "#333333";
    $scope.reverseName = function(){
     $scope.name = $scope.name.split("").reverse().join("");
    };
    $scope.randomColor = function(){
        $scope.color = '#'+Math.floor(Math.random()*16777215).toString(16);
    };
});
app.directive("myDirective", function(){
    return {
        restrict: "EA",
        scope: {
            name: "@",
            color: "=",
            reverse: "&"
        },
        link: function(element, scope, attrs){
           //do something like
           $scope.reverse(); 
          //calling the controllers function
        }
    };
});

I html (zauważ różnicę dla @ i =):

<div my-directive
  class="directive"
  name="{{name}}"
  reverse="reverseName()"
  color="color" >
</div>

Oto link do bloga, który ładnie go opisuje.

Kop4lyf
źródło
& nie jest ani „wiązaniem behawioralnym”, ani „wiązaniem metod”, jest wiązaniem wyrażenia kątowego.
Dmitri Zaitsev,
20

Po prostu możemy użyć: -

  1. @ : - dla wartości ciągu dla jednokierunkowego powiązania danych. w jeden sposób powiązanie danych można przekazać wartość zakresu tylko do dyrektywy

  2. = : - dla wartości obiektu dla dwukierunkowego powiązania danych. w dwukierunkowym powiązaniu danych możesz zmienić wartość zakresu w dyrektywie, a także w html.

  3. & : - dla metod i funkcji.

EDYTOWAĆ

W naszej definicji komponentu dla wersji kątowej 1.5 i wyższej
istnieją cztery różne typy powiązań:

  1. = Dwukierunkowe wiązanie danych : - jeśli zmienimy wartość, zostanie ona automatycznie zaktualizowana
  2. < wiązanie jednokierunkowe : - gdy chcemy po prostu odczytać parametr z zakresu nadrzędnego i nie aktualizować go.

  3. @dotyczy to parametrów ciągu

  4. &dotyczy to wywołań zwrotnych w przypadku, gdy komponent musi wyprowadzić coś do swojego nadrzędnego zakresu

ojus kulkarni
źródło
13

Stworzyłem mały plik HTML, który zawiera kod Angulara, pokazujący różnice między nimi:

<!DOCTYPE html>
<html>
  <head>
    <title>Angular</title>
    <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.3.15/angular.min.js"></script>
  </head>
  <body ng-app="myApp">
    <div ng-controller="myCtrl as VM">
      <a my-dir
        attr1="VM.sayHi('Juan')" <!-- scope: "=" -->
        attr2="VM.sayHi('Juan')" <!-- scope: "@" -->
        attr3="VM.sayHi('Juan')" <!-- scope: "&" -->
      ></a>
    </div>
    <script>
    angular.module("myApp", [])
    .controller("myCtrl", [function(){
      var vm = this;
      vm.sayHi = function(name){
        return ("Hey there, " + name);
      }
    }])
    .directive("myDir", [function(){
      return {
        scope: {
          attr1: "=",
          attr2: "@",
          attr3: "&"
        },
        link: function(scope){
          console.log(scope.attr1);   // =, logs "Hey there, Juan"
          console.log(scope.attr2);   // @, logs "VM.sayHi('Juan')"
          console.log(scope.attr3);   // &, logs "function (a){return h(c,a)}"
          console.log(scope.attr3()); // &, logs "Hey there, Juan"
        }
      }
    }]);
    </script>
  </body>
</html>
RobertAKARobin
źródło
6

= Sposobem jest wiążący 2-drożny , który pozwala mieć żywe zmian wewnątrz dyrektywy. Kiedy ktoś zmieni tę zmienną poza dyrektywę, będziesz mieć te zmienione dane w swojej dyrektywie, ale @ way nie jest wiążące w obie strony . Działa jak tekst . Wiążesz raz, a będziesz miał tylko jego wartość.

Aby uzyskać to jaśniej, możesz skorzystać z tego wspaniałego artykułu:

Dyrektywa AngularJS Zakres „@” i „=”

Hazarapet Tunanyan
źródło
6

To pytanie zostało już pobite na śmierć, ale i tak podzielę się nim na wypadek, gdyby ktoś jeszcze zmagał się z okropnym bałaganem, jakim są zakresy AngularJS. Pokrywa ta wola =, <, @, &i ::. Pełny opis można znaleźć tutaj .


=ustanawia wiązanie dwukierunkowe. Zmiana właściwości w obiekcie nadrzędnym spowoduje zmianę w obiekcie podrzędnym i odwrotnie.


<ustanawia wiązanie w jedną stronę, od rodzica do dziecka. Zmiana właściwości elementu nadrzędnego spowoduje zmianę elementu podrzędnego, ale zmiana właściwości elementu podrzędnego nie wpłynie na właściwość elementu nadrzędnego.


@przypisze do właściwości potomnej wartość ciągu atrybutu tagu. Jeśli atrybut zawiera wyrażenie , właściwość potomna jest aktualizowana za każdym razem, gdy wyrażenie zmienia się na inny ciąg. Na przykład:

<child-component description="The movie title is {{$ctrl.movie.title}}" />
bindings: {
    description: '@', 
}

Tutaj descriptionwłaściwość w zakresie podrzędnym będzie bieżącą wartością wyrażenia "The movie title is {{$ctrl.movie.title}}", gdzie moviejest obiektem w zakresie nadrzędnym.


&jest nieco podstępny i wydaje się, że nie ma istotnego powodu, aby kiedykolwiek z niego korzystać. Pozwala ocenić wyrażenie w zakresie nadrzędnym, zastępując parametry zmiennymi z zakresu podrzędnego. Przykład ( plunk ):

<child-component 
  foo = "myVar + $ctrl.parentVar + myOtherVar"
</child-component>
angular.module('heroApp').component('childComponent', {
  template: "<div>{{  $ctrl.parentFoo({myVar:5, myOtherVar:'xyz'})  }}</div>",
  bindings: {
    parentFoo: '&foo'
  }
});

Biorąc pod uwagę parentVar=10, wyrażenie parentFoo({myVar:5, myOtherVar:'xyz'})będzie oceniać, 5 + 10 + 'xyz'a komponent będzie renderowany jako:

<div>15xyz</div>

Kiedy chciałbyś kiedykolwiek skorzystać z tej zawiłej funkcjonalności? &jest często używany przez ludzi do przekazania do zakresu potomnego funkcji wywołania zwrotnego w zakresie nadrzędnym. W rzeczywistości jednak ten sam efekt można uzyskać, używając funkcji <, aby przekazać funkcję, co jest prostsze i pozwala uniknąć nieporęcznej składni nawiasów klamrowych w celu przekazania parametrów ( {myVar:5, myOtherVar:'xyz'}). Rozważać:

Oddzwonienie za pomocą &:

<child-component parent-foo="$ctrl.foo(bar)"/>
angular.module('heroApp').component('childComponent', {
  template: '<button ng-click="$ctrl.parentFoo({bar:'xyz'})">Call foo in parent</button>',
  bindings: {
    parentFoo: '&'
  }
});

Oddzwonienie za pomocą <:

<child-component parent-foo="$ctrl.foo"/>
angular.module('heroApp').component('childComponent', {
  template: '<button ng-click="$ctrl.parentFoo('xyz')">Call foo in parent</button>',
  bindings: {
    parentFoo: '<'
  }
});

Zauważ, że obiekty (i tablice) są przekazywane przez odniesienie do zakresu potomnego, a nie kopiowane. Oznacza to, że nawet jeśli jest to wiązanie jednokierunkowe, pracujesz z tym samym obiektem w zakresie nadrzędnym i podrzędnym.


Aby zobaczyć różne prefiksy w akcji, otwórz tę paczkę .

Łączenie jednorazowe (inicjowanie) przy użyciu ::

[Oficjalne dokumenty]
Późniejsze wersje AngularJS wprowadzają opcję posiadania powiązania jednorazowego, w którym właściwość zasięgu potomnego jest aktualizowana tylko raz. Poprawia to wydajność, eliminując potrzebę oglądania właściwości nadrzędnej. Składnia jest inna niż powyżej; aby zadeklarować powiązanie jednorazowe, dodajesz ::przed wyrażeniem w znaczniku komponentu :

<child-component 
  tagline = "::$ctrl.tagline">
</child-component>

Spowoduje to propagowanie wartości taglinedo zasięgu potomnego bez ustanawiania wiązania jednokierunkowego lub dwukierunkowego. Uwaga : jeśli taglinepoczątkowo znajduje się undefinedw zakresie nadrzędnym, kątowy będzie go obserwował, dopóki się nie zmieni, a następnie dokona jednorazowej aktualizacji odpowiedniej właściwości w zakresie podrzędnym.

Podsumowanie

Poniższa tabela pokazuje, jak działają przedrostki w zależności od tego, czy właściwość jest obiektem, tablicą, łańcuchem itp.

Jak działają różne powiązania zakresu izolowania

Mihail Kostira
źródło
4

@ właściwość zakresu lokalnego służy do uzyskiwania dostępu do wartości ciągów zdefiniowanych poza dyrektywą.

= W przypadkach, w których konieczne jest utworzenie dwukierunkowego powiązania między zakresem zewnętrznym a zakresem izolowania dyrektywy, można użyć znaku =.

& Właściwość zakresu lokalnego umożliwia konsumentowi dyrektywy przekazanie funkcji, którą dyrektywa może wywołać.

Prosimy sprawdzić poniższy link, który daje jasne zrozumienie przykładów. Uważam, że jest bardzo przydatny, więc pomyślałem o udostępnieniu go.

http://weblogs.asp.net/dwahlin/creating-custom-angularjs-directives-part-2-isolate-scope

Raphael
źródło
3

Nawet gdy zakres jest lokalny, jak w twoim przykładzie, możesz uzyskać dostęp do zakresu nadrzędnego za pośrednictwem właściwości $parent. Załóżmy w poniższym kodzie, który titlejest zdefiniowany w zakresie nadrzędnym. Następnie możesz uzyskać dostęp do tytułu jako $parent.title:

link : function(scope) { console.log(scope.$parent.title) },
template : "the parent has the title {{$parent.title}}"

Jednak w większości przypadków ten sam efekt lepiej uzyskać za pomocą atrybutów.

Przykład, w którym znalazłem notację „&”, która jest używana „do przekazywania danych z zakresu izolowanego za pomocą wyrażenia i do zakresu nadrzędnego”, użyteczny (i nie można zastosować dwukierunkowego wiązania danych) znajduje się w dyrektywie do renderowania specjalnej struktury danych w powtórzeniu ng.

<render data = "record" deleteFunction = "dataList.splice($index,1)" ng-repeat = "record in dataList" > </render>

Jedną częścią renderowania był przycisk usuwania i tutaj warto było dołączyć funkcję usuwania z zakresu zewnętrznego za pomocą &. Wewnątrz dyrektywy renderowania wygląda

scope : { data = "=", deleteFunction = "&"},
template : "... <button ng-click = "deleteFunction()"></button>"

Dwukierunkowe wiązanie danych, tzn. data = "="Nie może być użyte, ponieważ funkcja usuwania działałaby w każdym $digestcyklu, co nie jest dobre, ponieważ zapis jest natychmiast usuwany i nigdy nie renderowany.

użytkownik3750988
źródło
3

główna różnica między nimi jest sprawiedliwa

@ Attribute string binding
= Two-way model binding
& Callback method binding
Ashish Kamble
źródło
1

@i =zobacz inne odpowiedzi.

Jeden haczyka o TL; DR; pobiera wyrażenie (nie tylko funkcję jak w przykładach w innych odpowiedziach) od rodzica i ustawia je jako funkcję w dyrektywie, która wywołuje to wyrażenie. Ta funkcja ma możliwość zastąpienia dowolnej zmiennej (nawet nazwy funkcji) wyrażenia poprzez przekazanie obiektu zmiennymi. &

&

wyjaśnione
& jest wyrazem odniesienia, co oznacza, że jeśli coś przekazać jak <myDirective expr="x==y"></myDirective>
w dyrektywie, to exprbędzie to funkcja, która wymaga wyrażenia, jak:
function expr(){return x == y}.
więc w dyrektywie HTML <button ng-click="expr()"></button>wywoła wyrażenie. W js dyrektywy po prostu $scope.expr()wywoła to wyrażenie.
Wyrażenie zostanie wywołane z $ scope.x i $ scope.y rodzica.
Masz możliwość zastąpienia parametrów!
Jeśli ustawisz je przez wywołanie, np <button ng-click="expr({x:5})"></button>
. Wyrażenie zostanie wywołane z parametrem xi parametrem rodzica y.
Możesz zastąpić oba.
Teraz wiesz, dlaczego <button ng-click="functionFromParent({x:5})"></button>działa.
Ponieważ po prostu wywołuje wyrażenie rodzic (np<myDirective functionFromParent="function1(x)"></myDirective>) i zastępuje możliwe wartości określonymi parametrami, w tym przypadku x.
może to być:
<myDirective functionFromParent="function1(x) + 5"></myDirective>
albo
<myDirective functionFromParent="function1(x) + z"></myDirective>
z rozmowy dziecka:
<button ng-click="functionFromParent({x:5, z: 4})"></button>.
lub nawet zastąpienie funkcji:
<button ng-click="functionFromParent({function1: myfn, x:5, z: 4})"></button>.

to tylko wyrażenie, nie ma znaczenia, czy jest to funkcja, wiele funkcji, czy tylko porównanie. I możesz zastąpić dowolną zmienną tego wyrażenia.

Przykłady:
dyrektywa szablon vs zwanego kodem:
rodzic zdefiniowała $ scope.x, $ scope.y:
szablon nadrzędny: <myDirective expr="x==y"></myDirective>
<button ng-click="expr()"></button>rozmowy $scope.x==$scope.y
<button ng-click="expr({x: 5})"></button>rozmowy 5 == $scope.y
<button ng-click="expr({x:5, y:6})"></button>rozmowy5 == 6

rodzic zdefiniował $ scope.function1, $ scope.x, $ scope.y:
szablon nadrzędny:<myDirective expr="function1(x) + y"></myDirective>

<button ng-click="expr()"></button>połączeń $scope.function1($scope.x) + $scope.y
<button ng-click="expr({x: 5})"></button>połączeń $scope.function1(5) + $scope.y
<button ng-click="expr({x:5, y:6})"></button>Połączenia $scope.function1(5) + 6
dyrektywa ma $ scope.myFn jako funkcja:
<button ng-click="expr({function1: myFn, x:5, y:6})"></button> połączenia$scope.myFn(5) + 6

ya_dimon
źródło
0

Dlaczego muszę używać „{{title}}” z „@” i „title” z „=”?

Gdy używasz {{title}}, tylko wartość zakresu nadrzędnego zostanie przekazana do widoku dyrektywy i oceniona. Jest to ograniczone do jednego sposobu, co oznacza, że ​​zmiana nie zostanie odzwierciedlona w zakresie nadrzędnym. Możesz użyć „=”, jeśli chcesz odzwierciedlić zmiany wprowadzone w dyrektywie podrzędnej również w zakresie nadrzędnym. To jest dwukierunkowe.

Czy mogę również uzyskać bezpośredni dostęp do zakresu nadrzędnego, bez ozdabiania mojego elementu atrybutem?

Gdy dyrektywa ma atrybut scope (zakres: {}), nie będzie już można uzyskać bezpośredniego dostępu do zakresu nadrzędnego. Ale nadal można uzyskać do niego dostęp przez zakres. $ Parent itp. Jeśli usuniesz zakres z dyrektywy, możesz uzyskać do niego bezpośredni dostęp.

Dokumentacja mówi: „Często pożądane jest przekazywanie danych z izolowanego zakresu przez wyrażenie i do zakresu nadrzędnego”, ale wydaje się, że działa to dobrze również w przypadku wiązania dwukierunkowego. Dlaczego droga ekspresowa byłaby lepsza?

To zależy od kontekstu. Jeśli chcesz wywołać wyrażenie lub funkcję z danymi, korzystasz z &, a jeśli chcesz udostępniać dane, możesz skorzystać z dwustronnego sposobu, używając „=”

Różnice między wieloma sposobami przekazywania danych do dyrektywy znajdują się pod poniższym linkiem:

AngularJS - Lunety izolowane - @ vs = vs &

http://www.codeforeach.com/angularjs/angularjs-isolated-scopes-vs-vs

Prashanth
źródło
0

@ Powiązanie ciągu atrybutu (w jedną stronę) = Powiązanie modelu dwukierunkowego i powiązanie metody wywołania zwrotnego

Jatin Patel
źródło
0

@ wiąże właściwość zasięgu lokalnego / dyrektywy z oszacowaną wartością atrybutu DOM. = wiąże właściwość zakresu lokalnego / dyrektywy z właściwością zakresu nadrzędnego. & bindowanie służy do przekazania metody do zakresu dyrektywy, aby można ją było wywołać w ramach dyrektywy.

@ Powiązanie ciągu atrybutu = Powiązanie modelu dwukierunkowego i powiązanie metody wywołania zwrotnego

Ashish Kamble
źródło