ng-click não funciona dentro do modelo de uma diretiva

Noob angular aqui. Estou criando uma diretiva para exibir recursivamente uma tree de perguntas e subquestões. Eu estou usando um link no modelo que chama uma function dentro do escopo. Por algum motivo, ele não chama o método editQuestion() .

Aqui está o código e o violino 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()); } }; });

Qualquer ajuda para entender isso seria apreciada.

Você tem um problema de escopo. Como você usou o escopo isolado em sua diretiva com scope: { value: '=' } , ele não tem mais access ao escopo do seu controlador que tem o editQuestion .

Você precisa passar o editQuestion ao escopo da sua diretiva para saber como chamá-lo. Isso é tipicamente muito fácil, mas por causa de sua estrutura diretiva infinitamente recursiva, onde as opções podem include perguntas, fica um pouco mais complicado. Aqui está um violino de trabalho:

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

O HTML agora inclui uma referência ao editQuestion :

 

E sua diretiva questions agora espera um atributo onEdit em seu escopo:

 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 como estamos direcionando a question no ng-click . É assim que você direciona argumentos em funções de retorno de chamada. Observe também como na on-edit estamos passando para sua diretiva choices , estamos segmentando subQuestion . Isso porque a question já está reservada dentro do ngRepeat , então precisamos diferenciar entre os dois.

Este foi provavelmente o conceito mais difícil para eu aprender em Angular até agora. Depois de entender como o escopo funciona entre controladores, diretivas e outras diretrizes, o mundo de Angular é seu. 🙂

Este é um problema de escopo. O ng-click da diretiva chama os methods editQuestion & removeQuestion do escopo atual, que não existem no escopo da diretiva, pois são definidos no módulo que está incluindo a diretiva (isto é, o escopo pai).

Você quer estabelecer uma binding entre a diretiva e o pai, assim, quando, a diretiva chama a function ngClick, ela triggers no módulo que hospeda a diretiva.

Você pode definir os methods na própria diretiva ou vincular a configuração através da seção de escopo do object de definição da diretiva

Aqui está um plunker que ilustra triggersndo events de ng-click em diferentes escopos (saídas para console)

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

A resposta de Langdon em 10 de maio de 13 está correta. Para fins de demonstração, simplifiquei o código de violino de Langdon e o reduzi de 148 linhas angulares para 23 linhas angulares.
Eu também adicionei funcionalidade que permite passar um valor de parâmetro como um object MouseEvent através do método de chamada de function e recuperando o dito valor na function.

Aqui está o JSFIDDLE seguido pelo código e créditos, deve ser muito 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 não funciona dentro do modelo de uma diretiva

Mark Rajcok – AngularJS recebendo $ event de uma diretiva (Langdon também recebe uma ajuda para fazer a pergunta Mark Answers)

PavanAsTechie – Valor de atributo de access dentro da function de controlador não diretiva e JSFIDDLE de Pavan – http://jsfiddle.net/brettdewoody/FAeJq/ (notavelmente a seguinte linha de código de Pavan): alert(obj.target.attributes.data.value);

Para qualquer um que esteja fazendo isso e tentando fazer isso com o código que não está em execução na sua diretiva , verifique se você não está usando a opção replace .

Por exemplo:

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