问题
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>
回答1:
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
回答2:
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
回答3:
Instead of this:
<li ng-repeat="e in events">
<a ng-click="triggerTitle=e.name; triggerEvent = e.action;">{{e.action}} {{e.name}}</a>
</li>
Just do this:
<li ng-repeat="e in events">
<a ng-click="$parent.triggerTitle=e.name; $parent.triggerEvent = e.action;">{{e.action}} {{e.name}}</a>
</li>
ng-repeat
creates a new scope, you can use $parent
to access the parent scope from inside the ng-repeat
block.
回答4:
Here we can use $parent so that we can access the code outside of the ng-repeat.
Html code
<div ng-controller="MyCtrl">
<a ng-click="triggerTitle='This works!'">test</a>
<h5>Please select trigger event: [{{triggerEvent}}] {{triggerTitle}}</h5>
<br /> <br />
<ul class="dropdown-menu">
<li ng-repeat="e in events">
<a ng-click="$parent.triggerTitle=e.name; $parent.triggerEvent = e.action;">{{e.action}} - {{e.name}}</a>
</li>
</ul>
Angular Js code
var myApp = angular.module('myApp',[]);
function MyCtrl($scope) {
$scope.triggerTitle = 'Select Event';
$scope.triggerEvent = 'x';
$scope.triggerPeriod = 'Select Period';
$scope.events = [{action:'compare', name:'Makes a policy comparison'}, {action:'purchase', name:'Makes a purchase'},{action:'addToCart', name:'Added a product to the cart'}]
}
you can test it here http://jsfiddle.net/xVZEX/96/
回答5:
This Works
<body ng-app="demo" ng-controller="MainCtrl">
<ul>
<li ng-repeat="action in actions" ng-click="action.action()">{{action.name}}</li>
</ul>
<script>
angular.module('demo', ['ngRoute']);
var demo = angular.module('demo').controller('MainCtrl', function ($scope) {
$scope.actions = [
{ action: function () {
$scope.testabc();
}, name: 'foo'
},
{ action: function () {
$scope.testxyz();
}, name: 'bar'
}
];
$scope.testabc = function(){
alert("ABC");
};
$scope.testxyz = function(){
alert("XYZ");
};
});
</script>
</body>
回答6:
use this
<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>
I converted ng-click to ng:click and it started working, I am yet to find the reason, just quickly posted to share.
回答7:
I surfed the internet for so long looking for an answer to the problem of ng-repeat creating its own scope within it. When you change a variable inside ng-repeat, the views don't update everywhere else in the document.
And finally the solution I found was one word, and no one tells you that.
It's $parent. before the variable name and it will change its value in the global scope.
So
ng-click="entryID=1"
becomesng-click="$parent.entryID=1"
回答8:
Use controllers with the 'as' keyword.
Check the documentation on angularjs on controllers.
For the above question:
<div ng-controller="MyCtrl as myCntrl">
<a ng-click="myCntrl.triggerTitle='This works!'">test</a>
<h5>Please select trigger event: [{{myCntrl.triggerEvent}}] {{myCntrl.triggerTitle}}</h5>
<ul class="dropdown-menu">
<li ng-repeat="e in myCntrl.events">
<a ng-click="myCntrl.triggerTitle=e.name; myCntrl.triggerEvent = e.action;">{{e.action}} - {{e.name}}</a>
</li>
</ul>
</div>
This will attach the properties and functions to the scope of the controller.
来源:https://stackoverflow.com/questions/16736804/ng-click-doesnt-work-inside-ng-repeat