2013-05-10 19 views
38

Węzeł kątowy jest tutaj. Tworzę dyrektywę rekurencyjnie wyświetlającą drzewo pytań i pytań dodatkowych. Używam linku w szablonie, który wywołuje funkcję w zakresie. Z jakiegoś powodu nie wywołuje metody editQuestion().Polecenie ng-click nie działa w ramach szablonu dyrektywy

Oto kod i skrzypce http://jsfiddle.net/madhums/n9KNv/

HTML:

<div ng-controller="FormCtrl"> 
    <questions value="survey.questions"></questions> 
</div> 

Javascript:

var app = angular.module('myApp', []); 

function FormCtrl ($scope) { 
    $scope.editQuestion = function (question) { 
    alert('abc'); 
    }; 
    $scope.survey = { 
    // ... 
    } 
} 


app.directive('questions', function($compile) { 
    var tpl = '<ol ui-sortable' + 
    ' ng-model="value"' + 
    ' class="list">' + 
    ' <li ng-repeat="question in value | filter:search"' + 
    '  <a href="" class="question">' + 
    '  {{ question.name }}' + 
    '  </a>' + 
    '  <span class="muted">({{ question.type }})</span>' + 
    '  <a href="" class="danger" ng-click="removeQuestion(question)">remove</a>' + 
    '  <a href="" class="blue" ng-click="editQuestion(question)">edit</a>' + 
    '  <choices value="question.choices"></choices>' + 
    ' </li>' + 
    '</ol>'; 

    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 = '<ul class="abc" ng-repeat="choice in value">'+ 
    ' <li>' + 
    ' {{ choice.name }}' + 
    ' <span class="muted">' + 
    '  ({{ choice.questions.length }} questions)' + 
    ' </span>' + 
    '' + 
    ' <a href=""' + 
    '  ng-click="addQuestions(choice.questions)"' + 
    '  tooltip="add sub questions">' + 
    '  +' + 
    ' </a>' + 
    '' + 
    ' <questions value="choice.questions"></questions>' 
    ' </li>' + 
    '</ul>'; 

    return { 
    restrict: 'E', 
    terminal: true, 
    scope: { value: '=' }, 
    template: tpl, 
    link: function(scope, element, attrs) { 
     $compile(element.contents())(scope.$new()); 
    } 
    }; 
}); 

Każda pomoc w zrozumieniu tego będą mile widziane.

Odpowiedz

38

Masz problem z zasięgiem. Ponieważ w swojej dyrektywie zastosowano izolowany zakres z numerem scope: { value: '=' }, nie ma on już dostępu do zakresu kontrolera o numerze editQuestion.

Musisz podać editQuestion wraz z zakresem dyrektywy, aby wiedział, jak ją wywołać. Zazwyczaj jest to dość łatwe, ale z powodu nieskończenie rekursywnej struktury dyrektyw, w której wybory mogą zawierać pytania, staje się nieco trudniejsze. Oto skrzypce robocze:

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

HTML zawiera teraz odniesienie do editQuestion:

<div ng-controller="FormCtrl"> 
    <questions value="survey.questions" on-edit="editQuestion(question)"></questions> 
</div> 

A twój dyrektywa pytania oczekuje teraz atrybut onEdit w swoim zakresie:

app.directive('questions', function($compile) { 
    var tpl = '<ol ui-sortable' + 
    ' ng-model="value"' + 
    ' class="list">' + 
    ' <li ng-repeat="question in value | filter:search"' + 
    '  <a href="" class="question">' + 
    '  {{ question.name }}' + 
    '  </a>' + 
    '  <span class="muted">({{ question.type }})</span>' + 
     '  <a href="" class="blue" ng-click="onEdit({question: question})">edit</a>' + 
     '  <choices value="question.choices" on-edit="onEdit({question: subQuestion})"></choices>' + 
    ' </li>' + 
    '</ol>'; 

    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 = '<ul class="abc" ng-repeat="choice in value">'+ 
    ' <li>' + 
    ' {{ choice.name }}' + 
    ' <span class="muted">' + 
    '  ({{ choice.questions.length }} questions)' + 
    ' </span>' + 
    '' + 
     ' <questions value="choice.questions" on-edit="onEdit({subQuestion: question})"></questions>' 
    ' </li>' + 
    '</ul>'; 

    return { 
    restrict: 'E', 
    terminal: true, 
     scope: { value: '=', onEdit: '&' }, 
    template: tpl, 
    link: function(scope, element, attrs) { 
     $compile(element.contents())(scope.$new()); 
    } 
    }; 
}); 

Zwróć uwagę, że jesteśmy kierowani na question w ng-click. W ten sposób kierujesz argumenty do funkcji wywołania zwrotnego. Zwróć też uwagę na to, że w on-edit przechodzimy do dyrektywy choices, a my kierujemy się na subQuestion. Dzieje się tak, ponieważ question jest już zarezerwowany wewnątrz ngRepeat, więc musimy rozróżnić te dwa.

To była chyba najtrudniejsza dla mnie koncepcja nauki w Angular. Kiedy zrozumiesz, w jaki sposób działa między kontrolerami, dyrektywami i innymi dyrektywami, świat Angular jest twój.:)

+0

Dzięki. Wprowadziłem błąd przez dodanie do dyrektywy ng-click = "onEdit()". – Aravind

+0

@Langdon dzięki za udostępnienie. To pomogło mi rozwiązać problem, który miałem. W moim szablonie miałem i ciągle podawał błędy w parserze, dopóki nie wyjąłem nawiasów klamrowych wokół twowaybound.value po obejrzeniu twojego przykładu. –

8

To jest problem zakresu. Dyrektywa ng-click wywoływania metody removeQuestion bieżącego scope, które nie istnieją w zakresie dyrektywy, ponieważ są zdefiniowane w module, który zawiera dyrektywę (tj. Zakres nadrzędny).

Chcesz ustanowić powiązanie między dyrektywą a rodzicem, więc gdy dyrektywa wywoła funkcję ngClick, zostanie wywołana w module, który jest hostem dyrektywy.

Albo można zdefiniować metody w samej lub wiązanie przez sekcję zakresu directive definition object

Tutaj konfiguracji dyrektywy jest plunker który ilustruje wypalania ng kliknij wydarzenia w różnych zakresach (wyjścia do konsoli)

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

2

Langdon's May10 '13 Odpowiedź jest poprawna. Dla celów demonstracyjnych udoskonaliłem kod skrzypiec Langdona i sprowadziłem go z 148 linii kątowych do 23 linii kątowych.
Dodałem również funkcję, która umożliwia przekazywanie wartości parametru jako obiektu MouseEvent za pośrednictwem metody wywołania funkcji i pobieranie tej wartości w funkcji.

Oto JSFIDDLE, po którym następuje kod i napisy, powinno to być bardzo łatwe do naśladowania.

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

--Html--

<div ng-controller="FormCtrl"> 
    <questions on-edit="editQuestion(ev,question)" ></questions> 
</div> 

--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 = 
    '<span ng-click="onEdit({ev: $event, myName: question})" data="This sentence would probably be replaced with a mustache brace parameter, example: {{someValue}}, returning a value from the scope." style="cursor:pointer;">Click Me</span>'; 
    return { 
     restrict: 'E', 
     terminal: true, 
     scope: { onEdit: '&' }, 
     template: tpl, 
     link: function(scope, element, attrs) { 
      $compile(element.contents())(scope.$new()); 
     } 
    }; 
}); 

Uznania,
Langdon - ng-click doesn't work within the template of a directive

Mark Rajcok - AngularJS getting $event from a directive (Langdo n także dostaje pomoc dla zadać pytanie Mark ODPOWIEDZI)

PavanAsTechie - Access attribute value inside non-directive controller function i Pavan za JSFIDDLE - http://jsfiddle.net/brettdewoody/FAeJq/ (zwłaszcza następujący wiersz PAVAN za kodu): alert(obj.target.attributes.data.value);

1

każdemu przychodzi to z i próbuje zrobić z kodem to nie działa w Twojej dyrektywie, sprawdź, czy nie używasz opcji zamień.

Np

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

     $scope.clicked = function(){ 
     console.log("Clicked"); 
     } 
    } 
    }; 
} 
Powiązane problemy