0

I thought I have snytax or logic problem but after hours of debugging and I at least I found something regard my ng-click doesn't work. Below example demo ng-click tht within ng-repeat doesn't fire. (unless u create a function to fire it).

Look at this http://jsfiddle.net/tM56a/18/ then you know my problem.

html

<div ng-controller="apiCtrl">
    <p ng-click="show=!show">Click me I'm outside of li tags</p>

    <br />

    <ul>
        <li ng-repeat="menu in menus" >
            <a ng-click="show=true">click me, I am li tag</a>
        </li>
    </ul>

    <p ng-show="show">Show me text</p>

</div>

js

function apiCtrl($scope) {

    $scope.menus = [
        {menu: 'page_01', url: 'page_01.html'},
        {menu: 'page_02', url: 'page_02.html'}
    ];

    $scope.test = function(menu){
        alert('test ' + menu.url)
    }
}
noob
  • 101
  • 6

2 Answers2

2

You should use $parent.show:

<a ng-click="$parent.show=true">click me, I am li tag</a>   

The problem is , ng-repeat creates its own scope, which prototypically inherits parent scope. As show is boolean simple type, it makes problem for prototype inheritance. Read this to be aware of prototype inheritance and scope problems.

Community
  • 1
  • 1
Engineer
  • 47,849
  • 12
  • 88
  • 91
  • yup.. because I've nested json – noob Apr 16 '14 at 11:01
  • Read the link, I have provided. You can find the solutions in there.One of those, is you can declare setter/getter for `show` property in your root scope, and use them. – Engineer Apr 16 '14 at 11:03
  • @noob Of course, it should work, but it's not an elegant and generic solution. Usage of getter/setter is generic ,) – Engineer Apr 16 '14 at 11:23
  • @noob I meant like [this](http://jsfiddle.net/n5vs5/).In this case, it does not metter, how much nested `ng-repeat` is. – Engineer Apr 16 '14 at 11:34
  • yeah that is what I mean. now my problem solved! thank you. by that method no matter how ng-repeat i have i still can get it work! – noob Apr 16 '14 at 14:56
0

Quoting from the AngularJS wiki

Scope inheritance is normally straightforward, and you often don't even need to know it is happening... until you try 2-way data binding (i.e., form elements, ng-model) to a primitive (e.g., number, string, boolean) defined on the parent scope from inside the child scope. It doesn't work the way most people expect it should work. What happens is that the child scope gets its own property that hides/shadows the parent property of the same name. This is not something AngularJS is doing – this is how JavaScript prototypal inheritance works. New AngularJS developers often do not realize that ng-repeat, ng-switch, ng-view and ng-include all create new child scopes, so the problem often shows up when these directives are involved.

The problem is that you use a primitive (boolean). As the wiki suggests:

Having a '.' in your models will ensure that prototypal inheritance is in play. So, use
<input type="text" ng-model="someObj.prop1"> rather than
<input type="text" ng-model="prop1">.

If you really want/need to use a primitive, there are two workarounds:

  • Use $parent.parentScopeProperty in the child scope. This will prevent the child scope from creating its own property.
  • Define a function on the parent scope, and call it from the child, passing the primitive value up to the parent (not always possible)

Bottom line, you should either use an object, e.g. config.show instead show, or use $parent.show from within the child scope (ngRepeat-created <li>).

See, also, this short demo of the first alternative.

gkalpak
  • 47,844
  • 8
  • 105
  • 118