Appeler une fonction de contrôleur à partir d’une directive sans scope isolée dans AngularJS

Je n’arrive pas à trouver un moyen d’appeler une fonction sur la scope parent depuis une directive sans utiliser la scope isolée. Je sais que si j’utilise une scope isolée, je peux simplement utiliser “&” dans l’isolement pour accéder à la fonction sur la scope parente, mais l’utilisation de la scope isolée lorsque cela n’est pas nécessaire a des conséquences. Considérons le code HTML suivant:

 

Dans cet exemple simple, je souhaite afficher une boîte de dialog de confirmation JavaScript et appeler uniquement doIt () si elle clique sur “OK” dans la boîte de dialog de confirmation. C’est simple en utilisant une scope isolée. La directive ressemblerait à ceci:

 .directive('confirm', function () { return { ressortingct: 'A', scope: { confirm: '@', confirmAction: '&' }, link: function (scope, element, attrs) { element.bind('click', function (e) { if (confirm(scope.confirm)) { scope.confirmAction(); } }); } }; }) 

Mais le problème est que, parce que j’utilise la scope isolée, ng-hide dans l’exemple ci-dessus ne s’exécute plus dans la scope parent , mais plutôt dans la scope isolée (l’utilisation d’une scope isolée sur une directive entraîne toutes les directives sur cet élément). utiliser la scope isolée). Voici un jsFiddle de l’exemple ci-dessus où ng-hide ne fonctionne pas. (Notez que dans ce violon, le bouton devrait se cacher lorsque vous tapez “oui” dans la zone de saisie.)

L’alternative serait de ne PAS utiliser un champ d’application isolé , ce qui est en fait ce que je veux vraiment, car il n’est pas nécessaire d’isoler le champ d’application de cette directive. Le seul problème que j’ai est, comment puis-je appeler une méthode sur la scope parent si je ne la transmets pas sur une étendue isolée ?

Voici un jsfiddle où je n’utilise PAS la scope isolée et le ng-hide fonctionne correctement, mais, bien sûr, l’appel à confirmAction () ne fonctionne pas et je ne sais pas comment le faire fonctionner.

Veuillez noter que la réponse que je recherche vraiment est comment appeler des fonctions sur la scope externe SANS utiliser une étendue isolée. Et je ne suis pas intéressé par le fait que cette boîte de dialog de confirmation fonctionne d’une autre manière, car le but de cette question est de savoir comment passer des appels à la scope externe et pouvoir toujours faire fonctionner d’autres directives sur la scope parent.

Sinon, je serais intéressé d’entendre parler de solutions qui utilisent une scope isolée si d’autres directives vont toujours fonctionner contre la scope parente , mais je ne pense pas que cela soit possible.

Étant donné que la directive appelle uniquement une fonction (et ne tente pas de définir une valeur sur une propriété), vous pouvez utiliser $ eval au lieu de $ parse (avec une scope non isolée):

 scope.$apply(function() { scope.$eval(attrs.confirmAction); }); 

Ou mieux, utilisez simplement $ apply , qui affichera $ eval () par rapport à la scope:

 scope.$apply(attrs.confirmAction); 

Violon

Vous souhaitez utiliser le service $ parse dans AngularJS.

Donc pour votre exemple:

 .directive('confirm', function ($parse) { return { ressortingct: 'A', // Child scope, not isolated scope : true, link: function (scope, element, attrs) { element.bind('click', function (e) { if (confirm(attrs.confirm)) { scope.$apply(function(){ // $parse returns a getter function to be // executed against an object var fn = $parse(attrs.confirmAction); // In our case, we want to execute the statement in // confirmAction ie 'doIt()' against the scope // which this directive is bound to, because the // scope is a child scope, not an isolated scope. // The prototypical inheritance of scopes will mean // that it will eventually find a 'doIt' function // bound against a parent's scope. fn(scope, {$event : e}); }); } }); } }; }); 

Il y a un gotcha à faire pour définir une propriété en utilisant $ parse, mais je vais vous laisser traverser ce pont quand vous y arriverez.

Appelez explicitement hideButton sur la scope parent.

Voici le violon: http://jsfiddle.net/pXej2/5/

Et voici le HTML mis à jour:

 

Le seul problème que j’ai est, comment puis-je appeler une méthode sur la scope parent si je ne la transmets pas sur une étendue isolée?

Voici un jsfiddle où je n’utilise PAS la scope isolée et le ng-hide fonctionne bien, mais, bien sûr, l’appel à confirmAction () ne fonctionne pas et je ne sais pas comment le faire fonctionner.

Tout d’abord, un petit point: dans ce cas, la scope du contrôleur externe n’est pas la scope parente du champ d’application de la directive; la scope du contrôleur externe est la scope de la directive. En d’autres termes, les noms de variables utilisés dans la directive seront recherchés directement dans la scope du contrôleur.

Ensuite, écrire attrs.confirmAction() ne fonctionne pas car attrs.confirmAction pour ce bouton,

  

est la chaîne "doIt()" , et vous ne pouvez pas appeler une chaîne, par exemple "doIt()"() .

Votre question est vraiment:

Comment puis-je appeler une fonction lorsque j’ai son nom sous forme de chaîne?

En JavaScript, vous appelez principalement des fonctions utilisant la notation par points, comme ceci:

 some_obj.greet() 

Mais vous pouvez également utiliser la notation de tableau:

 some_obj['greet'] 

Notez comment la valeur d’index est une chaîne . Ainsi, dans votre directive, vous pouvez simplement faire ceci:

  link: function (scope, element, attrs) { element.bind('click', function (e) { if (confirm(attrs.confirm)) { var func_str = attrs.confirmAction; var func_name = func_str.subssortingng(0, func_str.indexOf('(')); // Or func_str.match(/[^(]+/)[0]; func_name = func_name.sortingm(); console.log(func_name); // => doIt scope[func_name](); } }); }