AngularJS - passa la funzione alla direttiva


160

Ho un esempio 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>

Voglio quando faccio clic sul pulsante, verrà visualizzata la finestra di avviso, ma non viene visualizzato nulla.

Qualcuno può aiutarmi?

Risposte:


243

Per chiamare una funzione del controller nell'ambito del genitore dall'interno di una direttiva dell'ambito dell'isolato, utilizzare i dash-separatednomi degli attributi nell'HTML come indicato dall'OP.

Inoltre, se si desidera inviare un parametro alla propria funzione, chiamare la funzione passando un oggetto:

<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
Ringrazio Codezilla per la risposta, e desidero chiedere le circostanze quando voglio associare la funzione "updateFn" dall'ambito padre per isolare l'ambito nel "test" della direttiva, è possibile?
user2707026

2
L' replaceattributo è stato disapprovato in AngularJS: stackoverflow.com/questions/24194972/...
cdmckay

8
per qualche ragione l'argomento non è definito per me.
Chovy

1
@chovy Penso che l'argomento sia usato solo dopo aver chiamato di nuovo il metodo? Il primo utilizzo della parentesi aperta sembra essere il formato che Angular vuole che il metodo venga appena passato, ma potrei sbagliarmi lì
MarkSzm,

1
Una mappatura di oggetti updateFn({msg: 'my message'});deve essere utilizzata in quel formato quando si effettua la chiamata di funzione all'interno della linkfunzione della direttiva .
Brian,

159

Forse mi manca qualcosa, ma sebbene le altre soluzioni chiamino la funzione dell'ambito padre non esiste la possibilità di passare argomenti dal codice della direttiva, ciò è dovuto al fatto che update-fnsta chiamando updateFn()con parametri fissi, ad esempio {msg: "Hello World"}. Una leggera modifica consente alla direttiva di passare argomenti, che ritengo molto più utili.

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

Nota che l'HTML sta passando un riferimento di funzione, ovvero senza ()parentesi.

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

Quindi, in quanto sopra, l'HTML sta chiamando la callUpdatefunzione di ambito locale , che quindi "recupera" updateFn dall'ambito padre e chiama la funzione restituita con parametri che la direttiva può generare.

http://jsfiddle.net/mygknek2/


9
Non sono sicuro di come posso ottenere un voto negativo per qualcosa che funziona ?? Dovresti lasciare un commento se vuoi votare in basso.
steve

7
Questo ha funzionato per me. Se non si desidera la funzione aggiuntiva, basta scrivereng-click="updateFn()('Directive Args')"
Graham Walters,

7
Awwww! scope.updateFn () ("Argomenti della direttiva"); !! NOT scope.updateFn ("Argomenti della direttiva"); !!!
Phung D. Un

2
Questa è davvero la risposta più perfetta !!
Vinesh,

11
@ Ludwik11 certo - è perché scope.updateFn quando definito in questo modo è una funzione che restituisce una funzione (quindi il () ()) e questo perché passiamo all'ambito (tramite update-fn = "updateFn" in html) un riferimento alla funzione che vogliamo chiamare. Il 1 ° () è una chiamata angolare per restituire questo riferimento, il 2 ° () effettua la chiamata alla nostra funzione ed è dove passiamo tutti i parametri. HTH
steve

39

Nel tag Html della direttiva "test", il nome dell'attributo della funzione non deve essere camelCased, ma basato su un trattino.

quindi - invece di:

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

Scrivi:

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

Questo è il modo in cui Angular rileva la differenza tra gli attributi della direttiva (come la funzione update-fn) e le funzioni.


1
grazie per la cattura. L'ho incluso nella mia risposta. Votato! :)
AlwaysALearner

10

Che ne dici di passare la funzione controller con associazione bidirezionale ? Quindi puoi usarlo nella direttiva esattamente allo stesso modo di un modello normale (ho rimosso parti irrilevanti per semplicità):

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

Sono arrivato a questa domanda, perché ho provato il metodo sopra accendendo, ma in qualche modo non ha funzionato. Ora funziona perfettamente.


5

usa trattino e lettere minuscole per il nome dell'attributo (come hanno detto altre risposte):

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

E usa "=" invece di "&" nell'ambito della direttiva:

 scope: { updateFn: '='}

Quindi puoi usare updateFn come qualsiasi altra funzione:

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

Ecco qua!


5
Perché dovresti usare '=' invece di '&'? quando l'ho provato ha continuato a chiamare ripetutamente la mia funzione.
user1012500,

2
È sbagliato usare '=' per questo. Questo è per il binding di oggetti a due vie.
Ben Taliadoros,

1
Penso che l'unico problema sia l'uso delle parentesi nel primo modello. Questo esegue la funzione quindi lega il risultato. Invece dovresti passare solo il nome della funzione, in questo modo:update-fn="updateFn"
Márton Tamás

1
Cattiva risposta. molto brutto.
rimorchiante

4

Ho dovuto usare l'associazione "=" invece di "&" perché non funzionava. Strano comportamento.


2
Questo perché molto probabilmente stai passando alla direttiva un riferimento alla funzione JS anziché all'esecuzione. Quando si passa la funzione come argomento alla direttiva update-fn="updateFn()"è necessario includere la parentesi (e forse i parametri). Passandolo come riferimento di funzioneupdate-fn="updateFn" non funzionerà con l' &associazione
JorgeGRC,

0

@JorgeGRC Grazie per la risposta. Una cosa però, la parte "forse" è molto importante. Se si dispone di parametri, è necessario includerli anche nel modello e assicurarsi di specificare i locali, ad es updateFn({msg: "Directive Args"}.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.