ng-click no funciona dentro de la plantilla de una directiva

Noob angular aquí. Estoy creando una directiva para mostrar recursivamente un árbol de preguntas y preguntas secundarias. Estoy usando un enlace en la plantilla que llama a una función dentro del scope. Por alguna razón, no llama al método editQuestion() .

Aquí está el código y el violín http://jsfiddle.net/madhums/n9KNv/

HTML:

 

Javascript:

 var app = angular.module('myApp', []); function FormCtrl ($scope) { $scope.editQuestion = function (question) { alert('abc'); }; $scope.survey = { // ... } } app.directive('questions', function($compile) { var tpl = '
    ' + ' <li ng-repeat="question in value | filter:search"' + ' ' + ' {{ question.name }}' + ' ' + ' ({{ question.type }})' + ' remove' + ' edit' + ' ' + ' ' + '
'; return { restrict: 'E', terminal: true, scope: { value: '=' }, template: tpl, link: function(scope, element, attrs) { $compile(element.contents())(scope.$new()); } }; }); app.directive('choices', function($compile) { var tpl = '
    '+ '
  • ' + ' {{ choice.name }}' + ' ' + ' ({{ choice.questions.length }} questions)' + ' ' + '' + ' ' + ' +' + ' ' + '' + ' ' '
  • ' + '
'; return { restrict: 'E', terminal: true, scope: { value: '=' }, template: tpl, link: function(scope, element, attrs) { $compile(element.contents())(scope.$new()); } }; });

Cualquier ayuda para entender esto sería apreciada.

Tienes un problema de scope. Como utilizó el scope aislado en su directiva con el scope: { value: '=' } , ya no tiene acceso al scope de su controlador que tiene editQuestion .

editQuestion pasar editQuestion junto con el scope de su directiva para que sepa cómo llamarlo. Esto es generalmente bastante fácil, pero debido a su estructura directiva infinitamente recursiva donde las opciones pueden incluir preguntas, se vuelve un poco más complicado. Aquí hay un violín que funciona:

http://jsfiddle.net/n9KNv/14/

El HTML ahora incluye una referencia a editQuestion :

 

Y su directiva de preguntas ahora espera un atributo onEdit en su scope:

 app.directive('questions', function($compile) { var tpl = '
    ' + '
  1. ' + ' {{ question.name }}' + ' ' + ' ({{ question.type }})' + ' edit' + ' ' + '
  2. ' + '
'; return { restrict: 'E', terminal: true, scope: { value: '=', onEdit: '&' }, template: tpl, link: function(scope, element, attrs) { $compile(element.contents())(scope.$new()); } }; }); app.directive('choices', function($compile) { var tpl = '
    '+ '
  • ' + ' {{ choice.name }}' + ' ' + ' ({{ choice.questions.length }} questions)' + ' ' + '' + ' ' '
  • ' + '
'; return { restrict: 'E', terminal: true, scope: { value: '=', onEdit: '&' }, template: tpl, link: function(scope, element, attrs) { $compile(element.contents())(scope.$new()); } }; });

Observe cómo estamos enfocando la question en ng-click . Así es como se dirigen los argumentos en las funciones de callback. También observe cómo en el proceso on-edit que estamos pasando a su directiva de choices , estamos apuntando a la subQuestion . Esto se debe a que la question ya está reservada dentro de ngRepeat , por lo que debemos diferenciar entre los dos.

Este fue probablemente el concepto más difícil de aprender en Angular hasta ahora. Una vez que comprenda cómo funciona el scope entre controladores, directivas y otras directivas, el mundo de Angular es suyo. 🙂

Este es un problema de scope. El ng-click de la directiva llama a los métodos editQuestion & removeQuestion del scope actual, que no existen en el ámbito de la directiva, ya que se definen en el módulo que incluye la directiva (es decir, el scope principal).

Desea establecer un enlace entre la directiva y el principal, de modo que cuando la directiva llame a la función ngClick, se active en el módulo que aloja la directiva.

O puede definir los métodos en la directiva en sí o configurar el enlace a través de la sección de scope del objeto de definición de directiva

Aquí hay un plunker que ilustra los eventos de disparar ng-click en diferentes ámbitos (salidas a la consola)

http://plnkr.co/edit/9XfXCpU6lhUOqD6nbVuQ?p=preview

La respuesta de Langdon May10 ’13 es correcta. Con fines de demostración, optimicé el código de violín de Langdon y lo bajé de 148 líneas de angular a 23 líneas de angular.
También agregué una funcionalidad que permite pasar un valor de parámetro como un objeto MouseEvent a través del método de llamada a función y recuperar dicho valor en la función.

Aquí está el JSFIDDLE seguido del código y los créditos, debería ser muy fácil de seguir.

http://jsfiddle.net/BeyondLogical/evjzoo30/

–Html–

 

–AngularJS–

 var app = angular.module('myApp', []); function FormCtrl ($scope) { $scope.editQuestion = function (ev,question) { //ev returns a MouseEvent object alert("ev: " + ev); //this is how you get the 'data' attribute set in the span tag below alert("ev-data: " + ev.target.attributes.data.value); }; } app.directive('questions', function($compile) { var tpl = 'Click Me'; return { restrict: 'E', terminal: true, scope: { onEdit: '&' }, template: tpl, link: function(scope, element, attrs) { $compile(element.contents())(scope.$new()); } }; }); 

Créditos para,
Langdon – ng-click no funciona dentro de la plantilla de una directiva

Mark Rajcok – AngularJS obtiene $ evento de una directiva (Langdon también recibe ayuda para hacer la pregunta Mark Answers)

PavanAsTechie: valor de atributo de acceso dentro de la función de controlador no directiva y JSFIDDLE de Pavan – http://jsfiddle.net/brettdewoody/FAeJq/ (en particular, la siguiente línea de código de Pavan): alert(obj.target.attributes.data.value);

Para cualquiera que intente hacerlo y trate de hacerlo con un código que no se esté ejecutando en su directiva , verifique que no esté utilizando la opción reemplazar .

P.ej:

 angular.module('app').directive('myDirective', function () { return { template: '
', scope: { options: "=" }, replace: true, //<---- Change this to false restrict: 'E', controller: function ($scope) { $scope.clicked = function(){ console.log("Clicked"); } } }; }