AngularJS - przekazuje funkcję do dyrektywy


160

Mam przykład angularJS

<div ng-controller="testCtrl">

<test color1="color1" updateFn="updateFn()"></test>
</div>
 <script>
  angular.module('dr', [])
.controller("testCtrl", function($scope) {
    $scope.color1 = "color";
    $scope.updateFn = function() {
        alert('123');
    }
})
.directive('test', function() {
    return {
        restrict: 'E',
        scope: {color1: '=',
                updateFn: '&'},
        template: "<button ng-click='updateFn()'>Click</button>",
        replace: true,
        link: function(scope, elm, attrs) { 
        }
    }
});

</script>
</body>

</html>

Chcę, aby po kliknięciu przycisku pojawiło się okno alertu, ale nic się nie pokazuje.

Czy ktoś może mi pomóc?

Odpowiedzi:


243

Aby wywołać funkcję kontrolera w zakresie nadrzędnym z wnętrza dyrektywy zakresu izolowanego, użyj dash-separatednazw atrybutów w kodzie HTML, tak jak powiedział OP.

Również jeśli chcesz wysłać parametr do swojej funkcji, wywołaj funkcję, przekazując obiekt:

<test color1="color1" update-fn="updateFn(msg)"></test>

JS

var app = angular.module('dr', []);

app.controller("testCtrl", function($scope) {
    $scope.color1 = "color";
    $scope.updateFn = function(msg) {        
        alert(msg);
    }
});

app.directive('test', function() {
    return {
        restrict: 'E',
        scope: {
            color1: '=',
            updateFn: '&'
        },
        // object is passed while making the call
        template: "<button ng-click='updateFn({msg : \"Hello World!\"})'>
            Click</button>",
        replace: true,        
        link: function(scope, elm, attrs) {             
        }
    }
});

Fiddle


1
Dziękuję Codezilli za odpowiedź i chcę zapytać o sytuację, w której chcę powiązać funkcję „updateFn” z zakresu nadrzędnego w celu izolowania zakresu w dyrektywie „test”, czy to możliwe?
user2707026

2
replaceAtrybut została zaniechana w angularjs: stackoverflow.com/questions/24194972/...
cdmckay

8
z jakiegoś powodu argument jest dla mnie niezdefiniowany.
chovy

1
@chovy Myślę, że argument jest używany tylko po ponownym wywołaniu metody? Pierwsze użycie otwartego nawiasu wydaje się być formatem, którego Angular chce, aby metoda została właśnie przekazana, ale mogę się mylić
marksyzm

1
Odwzorowanie obiektu updateFn({msg: 'my message'});musi być użyte w tym formacie podczas wywoływania funkcji wewnątrz funkcji dyrektywy link.
Brian

159

Być może czegoś mi brakuje, ale chociaż inne rozwiązania wywołują funkcję zakresu nadrzędnego, nie ma możliwości przekazywania argumentów z kodu dyrektywy, dzieje się tak dlatego, że update-fnwywołuje updateFn()ze stałymi parametrami, na przykład {msg: "Hello World"}. Niewielka zmiana pozwala dyrektywie na przekazywanie argumentów, co moim zdaniem jest o wiele bardziej przydatne.

<test color1="color1" update-fn="updateFn"></test>

Zauważ, że kod HTML przekazuje odwołanie do funkcji, tj. Bez ()nawiasów.

JS

var app = angular.module('dr', []);

app.controller("testCtrl", function($scope) {
    $scope.color1 = "color";
    $scope.updateFn = function(msg) {        
        alert(msg);
    }
});

app.directive('test', function() {
    return {
        restrict: 'E',
        scope: {
            color1: '=',
            updateFn: '&'
        },
        // object is passed while making the call
        template: "<button ng-click='callUpdate()'>
            Click</button>",
        replace: true,        
        link: function(scope, elm, attrs) {       
          scope.callUpdate = function() {
            scope.updateFn()("Directive Args");
          }
        }
    }
});

Tak więc w powyższym HTML wywołuje callUpdatefunkcję lokalnego zakresu , która następnie „pobiera” updateFn z zakresu nadrzędnego i wywołuje zwróconą funkcję z parametrami, które może wygenerować dyrektywa.

http://jsfiddle.net/mygknek2/


9
Nie wiesz, jak mogę uzyskać negatywny głos na coś, co działa? Powinieneś zostawić komentarz, jeśli zamierzasz głosować w dół.
steve

7
To zadziałało dla mnie. Jeśli nie chcesz dodatkowej funkcji, po prostu napiszng-click="updateFn()('Directive Args')"
Graham Walters

7
Awwww! scope.updateFn () ("Argumenty dyrektywy"); !! NOT scope.updateFn ("Argumenty dyrektywy"); !!!
Phung D. An

2
To jest rzeczywiście doskonalsza odpowiedź !!
vinesh

11
@ Ludwik11 pewnie - to dlatego, że scope.updateFn zdefiniowany w ten sposób jest funkcją, która zwraca funkcję (stąd () ()), a to dlatego, że przekazujemy do zakresu (przez update-fn = "updateFn" w html) referencję do funkcji, którą chcemy wywołać. Pierwsza () jest wywołaniem angular, aby zwrócić to odniesienie, druga () wywołuje naszą funkcję i jest tam, gdzie przekazujemy wszelkie parametry. HTH
steve

39

W tagu Html z dyrektywą „test” nazwa atrybutu funkcji nie powinna być wartością typu camelCased, ale oparta na myślniku.

so - zamiast:

<test color1="color1" updateFn="updateFn()"></test>

pisać:

<test color1="color1" update-fn="updateFn()"></test>

Jest to kątowy sposób na określenie różnicy między atrybutami dyrektywy (takimi jak funkcja update-fn) a funkcjami.


1
dzięki za połów. Zawarłem to w mojej odpowiedzi. Zagłosowano! :)
AlwaysALearner

10

Co powiesz na przekazanie funkcji kontrolera z powiązaniem dwukierunkowym ? Następnie możesz go użyć w dyrektywie dokładnie tak samo, jak w zwykłym szablonie (dla uproszczenia usunąłem nieistotne części):

<div ng-controller="testCtrl">

   <!-- pass the function with no arguments -->
   <test color1="color1" update-fn="updateFn"></test>
</div>

<script>
   angular.module('dr', [])
   .controller("testCtrl", function($scope) {
      $scope.updateFn = function(msg) {
         alert(msg);
      }
   })
   .directive('test', function() {
      return {
         scope: {
            updateFn: '=' // '=' bidirectional binding
         },
         template: "<button ng-click='updateFn(1337)'>Click</button>"
      }
   });
</script>

Wylądowałem na tym pytaniu, ponieważ wypróbowałem powyższą metodę befire, ale jakoś nie zadziałała. Teraz działa idealnie.


5

użyj myślnika i małych liter dla nazwy atrybutu (jak powiedziano w innych odpowiedziach):

 <test color1="color1" update-fn="updateFn()"></test>

I użyj „=” zamiast „&” w zakresie dyrektywy:

 scope: { updateFn: '='}

Następnie możesz użyć updateFn jak każdej innej funkcji:

 <button ng-click='updateFn()'>Click</button>

Proszę bardzo!


5
Dlaczego miałbyś używać „=” zamiast „&”? kiedy próbowałem tego, ciągle wywoływało moją funkcję.
user1012500

2
Używanie do tego znaku „=” jest niewłaściwe. To jest dla dwukierunkowego wiązania obiektów.
Ben Taliadoros

1
Myślę, że jedynym problemem jest użycie nawiasów w pierwszym szablonie. To wykonuje funkcję, a następnie wiąże wynik. Zamiast tego należy podać tylko nazwę funkcji, na przykład:update-fn="updateFn"
Márton Tamás

1
Zła odpowiedź. bardzo źle.
holowanie

4

Musiałem użyć wiązania „=” zamiast „&”, ponieważ to nie działało. Dziwne zachowanie.


2
Dzieje się tak, ponieważ najprawdopodobniej przekazujesz dyrektywie odwołanie do funkcji JS zamiast wykonania. Kiedy przekazujesz funkcję jako argument do dyrektywy update-fn="updateFn()", musisz dołączyć nawias (i być może parametry). Przekazywanie go jako odniesienia do funkcji update-fn="updateFn"nie zadziała z &wiązaniem
JorgeGRC,

0

@JorgeGRC Dzięki za odpowiedź. Jedna rzecz, jednak część „może” jest bardzo ważna. Jeśli masz parametr (y), musisz uwzględnić je / je również w swoim szablonie i upewnij się, że określisz swoje lokalne ustawienia, np updateFn({msg: "Directive Args"}.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.