Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Angular noob here. I am creating a directive to recursively display a tree of questions and sub questions. I am using a link in the template which calls a function within the scope. For some reason, it does't call the editQuestion() method.

Here's the code and the fiddle 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());     }   }; }); 

Any help in understanding this would be appreciated.

like image 925
Madhusudhan Avatar asked May 10 '13 18:05

Madhusudhan


People also ask

What is the difference between Ng-click and Onclick?

Another significant difference between ng-click and onclick is the execution context. Code inside an onclick attribute executes against the global window object, while an expression inside of ng-click executes against a specific scope object, typically the scope object representing the model for the current controller.

Can we use NG-click and Onclick together?

For a single btn, it's ok to use ng-click or onclick in the ng-app . There is no difference between the two functions. For effective team work, you,d better to have an account with each other. In Angular apps, ng-click is recommended.

What can I use instead of NG-repeat?

You can consider using transclusion inside a custom directive, to achieve the behavior you are looking for without using ng-repeat.

What is required with Ng include directive?

The ng-include directive includes HTML from an external file. The included content will be included as childnodes of the specified element. The value of the ng-include attribute can also be an expression, returning a filename. By default, the included file must be located on the same domain as the document.


1 Answers

You've got a scope issue. Since you used isolated scope in your directive with scope: { value: '=' }, it no longer has access to your controller's scope that has editQuestion.

You need to pass editQuestion along to your directive's scope so it knows how to call it. This is typically pretty easy, but because of your infinitely recursive directive structure where choices can include questions, it gets a bit trickier. Here's a working fiddle:

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

The HTML now includes a reference to editQuestion:

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

And your questions directive now expects an onEdit attribute in its scope:

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

Notice how we're targeting question in the ng-click. This is how you target arguments in callback functions. Also notice how in the on-edit we're passing to your choices directive, we're targeting subQuestion. This is because question is already reserved inside of the ngRepeat, so we need to differentiate between the two.

This was probably the hardest concept for me to learn in Angular so far. Once you understand how scope works between controllers, directives, and other directives, the world of Angular is yours. :)

like image 146
Langdon Avatar answered Sep 30 '22 00:09

Langdon