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?

user2707026
źródło

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

AlwaysALearner
źródło
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/

steve
źródło
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.

Ofer Segev
źródło
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.

Márton Tamás
źródło
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!

Jane
źródło
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.

Gunter Reinitzer
źródło
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"}.

user2893858
źródło