AngularJS - Funktion an Direktive übergeben

160

Ich habe ein Beispiel angleJS

<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>

Ich möchte, wenn ich auf die Schaltfläche klicke, wird das Warnfeld angezeigt, aber es wird nichts angezeigt.

Kann mir jemand helfen?

user2707026
quelle

Antworten:

243

Verwenden Sie dash-separatedAttributnamen im HTML-Code, wie im OP angegeben, um eine Controller-Funktion im übergeordneten Bereich innerhalb einer Direktive für den isolierten Bereich aufzurufen .

Wenn Sie einen Parameter an Ihre Funktion senden möchten, rufen Sie die Funktion auf, indem Sie ein Objekt übergeben:

<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
quelle
1
Vielen Dank an Codezilla für Ihre Antwort, und ich möchte nach dem Umstand fragen, wann ich die Funktion "updateFn" vom übergeordneten Bereich binden möchte, um den Bereich in der Direktive "test" zu isolieren. Ist das möglich?
user2707026
2
Das replaceAttribut ist in AngularJS veraltet: stackoverflow.com/questions/24194972/…
cdmckay
8
Aus irgendeinem Grund ist das Argument für mich undefiniert.
Chovy
1
@chovy Ich denke, das Argument wird nur verwendet, wenn Sie die Methode erneut aufrufen? Die erste Verwendung offener Klammern scheint das Format zu sein, das eckig sein soll, damit die Methode nur übergeben wird, aber ich könnte mich dort irren
marksyzm
1
Eine Objektzuordnung updateFn({msg: 'my message'});muss in diesem Format verwendet werden, wenn der Funktionsaufruf innerhalb der linkFunktion der Direktive ausgeführt wird .
Brian
159

Vielleicht fehlt mir etwas, aber obwohl die anderen Lösungen die übergeordnete Bereichsfunktion aufrufen, gibt es keine Möglichkeit, Argumente aus dem Direktivencode zu übergeben. Dies liegt beispielsweise daran, dass der update-fnAufruf updateFn()mit festen Parametern ausgeführt wird {msg: "Hello World"}. Eine geringfügige Änderung ermöglicht es der Richtlinie, Argumente zu übergeben, was ich für weitaus nützlicher halte.

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

Beachten Sie, dass der HTML-Code eine Funktionsreferenz übergibt, dh ohne ()Klammern.

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");
          }
        }
    }
});

Im obigen Beispiel ruft der HTML- callUpdateCode die lokale Bereichsfunktion auf , die dann das updateFn aus dem übergeordneten Bereich abruft und die zurückgegebene Funktion mit Parametern aufruft, die die Direktive generieren kann.

http://jsfiddle.net/mygknek2/

Steve
quelle
9
Nicht sicher, wie ich eine Abwertung für etwas bekommen kann, das funktioniert? Sie sollten einen Kommentar hinterlassen, wenn Sie abstimmen möchten.
Steve
7
Das hat bei mir funktioniert. Wenn Sie die zusätzliche Funktion nicht möchten, schreiben Sie einfachng-click="updateFn()('Directive Args')"
Graham Walters
7
Awwww! scope.updateFn () ("Direktivenargumente"); !! NOT scope.updateFn ("Direktivenargumente"); !!!
Phung D. An
2
Dies ist in der Tat eine perfektere Antwort !!
Vinesh
11
@ Ludwik11 sicher - es liegt daran, dass scope.updateFn, wenn es so definiert ist, eine Funktion ist, die eine Funktion zurückgibt (daher das () ()), und dies liegt daran, dass wir (über update-fn = "updateFn" in HTML) eine Referenz an scope übergeben zu der Funktion, die wir aufrufen möchten. Das 1st () ist ein Aufruf von Angular, um diese Referenz zurückzugeben, das 2nd () ruft unsere Funktion auf und übergibt alle Parameter. HTH
Steve
39

In Ihrem HTML-Tag der 'test'-Direktive sollte der Attributname der Funktion nicht camelCased, sondern dash-basiert sein.

also - statt:

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

schreiben:

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

Auf diese Weise kann Angular den Unterschied zwischen Direktivenattributen (z. B. update-fn-Funktion) und Funktionen erkennen.

Ofer Segev
quelle
1
Danke für den Fang. Ich habe das in meine Antwort aufgenommen. Abgestimmt! :)
AlwaysALearner
10

Wie wäre es, die Controller-Funktion mit bidirektionaler Bindung zu übergeben ? Dann können Sie es in der Direktive genauso verwenden wie in einer regulären Vorlage (ich habe der Einfachheit halber irrelevante Teile entfernt):

<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>

Ich bin bei dieser Frage gelandet, weil ich die oben beschriebene Methode ausprobiert habe, aber irgendwie hat es nicht funktioniert. Jetzt funktioniert es perfekt.

Márton Tamás
quelle
4

Verwenden Sie für den Attributnamen Bindestrich und Kleinbuchstaben (wie in anderen Antworten angegeben):

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

Und verwenden Sie "=" anstelle von "&" im Richtlinienumfang:

 scope: { updateFn: '='}

Dann können Sie updateFn wie jede andere Funktion verwenden:

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

Los geht's!

Jane
quelle
5
Warum würden Sie '=' anstelle von '&' verwenden? Als ich das versuchte, rief es immer wieder meine Funktion auf.
user1012500
2
Es ist falsch, dafür '=' zu verwenden. Das ist für die bidirektionale Objektbindung.
Ben Taliadoros
1
Ich denke, das einzige Problem ist die Verwendung von Klammern in der ersten Vorlage. Dies führt die Funktion aus und bindet dann das Ergebnis. Stattdessen sollten Sie nur den Namen der Funktion wie folgt übergeben:update-fn="updateFn"
Márton Tamás
2
Falsche Antwort. sehr schlecht.
Towry
4

Ich musste die Bindung "=" anstelle von "&" verwenden, da dies nicht funktionierte. Seltsames Verhalten.

Gunter Reinitzer
quelle
3
Dies liegt daran, dass Sie der Direktive höchstwahrscheinlich eine JS-Funktionsreferenz anstelle der Ausführung übergeben. Wenn Sie die Funktion als Argument an die Direktive übergeben update-fn="updateFn()", müssen Sie die Klammern (und möglicherweise die Parameter) einfügen. Das Übergeben als Funktionsreferenz funktioniert update-fn="updateFn"nicht mit der &Bindung
JorgeGRC
0

@JorgeGRC Danke für deine Antwort. Eines ist jedoch der "vielleicht" Teil sehr wichtig. Wenn Sie Parameter haben, müssen Sie diese auch in Ihre Vorlage aufnehmen und Ihre Einheimischen angeben, z updateFn({msg: "Directive Args"}.

user2893858
quelle