Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ng-click doesn't work inside ng-repeat

Ng-click doesn't work from inside ng-repeat. Outside it works. I've put a fiddle here

<div ng-controller="MyCtrl">  <a ng-click="triggerTitle='This works!'">test</a>     <h5>Please select trigger event: [{{triggerEvent}}] {{triggerTitle}}</h5>        <ul class="dropdown-menu">          <li ng-repeat="e in events">              <a ng-click="triggerTitle=e.name; triggerEvent = e.action;">{{e.action}} - {{e.name}}</a>          </li>        </ul> </div> 
like image 898
Alexandru R Avatar asked May 24 '13 14:05

Alexandru R


People also ask

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.

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.

How do I get an index in NG-repeat?

Note: The $index variable is used to get the Index of the Row created by ng-repeat directive. Each row of the HTML Table consists of a Button which has been assigned ng-click directive. The $index variable is passed as parameter to the GetRowIndex function.

Does ng-repeat create a new scope?

Directives that Create Scopes In most cases, directives and scopes interact but do not create new instances of scope. However, some directives, such as ng-controller and ng-repeat, create new child scopes and attach the child scope to the corresponding DOM element.


2 Answers

As Ven mentioned, ng-repeat does create a child scope for each item in the loop. The child scopes do have access to the parent scope's variables and methods through prototypal inheritance. The confusing part is when you make an assignment, it adds a new variable to the child scope rather than updating the property on the parent scope. In ng-click, when you make an assignment call tiggerTitle =e.name, it actually adds a new variable called triggerTitle to the child scope. The AngularJS docs explains this well in the section here called JavaScript Prototypal Inheritance.

So how do you get around this and set the model variable properly?

A quick and dirty solution is to access the parent scope using $parent like so.

<a ng:click="$parent.triggerTitle=e.name; $parent.triggerEvent = e.action;">... 

Click to see a working version of your Fiddle using the $parent solution.

The use of $parent can cause issues if you are dealing with nested templates or nested ng-repeats. A better solution may be to add a function to the controller's scope which returns a reference to the controller's scope. As already mentioned, the child scopes have access to call the parent functions, and thus can reference the controller's scope.

function MyCtrl($scope) {     $scope.getMyCtrlScope = function() {          return $scope;        }  ...  <a ng-click="getMyCtrlScope().triggerTitle=e.name;getMyCtrlScope().triggerEvent = ... 

Click to see a working version of your Fiddle using the better method

like image 120
James Lawruk Avatar answered Sep 23 '22 13:09

James Lawruk


Because ng-repeat creates a new scope.

This has been answered numerous time, because the nuance is a bit difficult to understand, especially if you don't know everything about js's prototypal inheritance : https://github.com/angular/angular.js/wiki/Understanding-Scopes

EDIT: it seems this answer is very controversial. Just to be clear – this is how JS works. You really shouldn't try to learn Angular before understand how JS works. However, the link does seem to miss

So, here's an example on how JS works in this case:

var a = {value: 5}; var b = Object.create(a); // create an object that has `a` as its prototype  // we can access `value` through JS' the prototype chain alert(b.value); // prints 5 // however, we can't *change* that value, because assignment is always on the designated object b.value = 10; alert(b.value); // this will print 10... alert(a.value); // ... but this will print 5! 

So, how can we work around that?

Well, we can "force" ourselves to go through the inheritance chain – and thus we'll be sure we're always accessing the correct object, whether accessing value or modifying it.

var a = {obj: {value: 5}}; var b = Object.create(a); // create an object that has `a` as its prototype  // we can access `value` through JS' the prototype chain: alert(b.obj.value); // prints 5 // and if we need to change it, // we'll just go through the prototype chain again: b.obj.value = 10; // and actually refer to the same object!  alert(b.obj.value == a.obj.value); // this will print true 
like image 36
Ven Avatar answered Sep 23 '22 13:09

Ven