【问题标题】:Ng-click doesn't work inside ng-repeatng-click 在 ng-repeat 中不起作用
【发布时间】:2013-05-24 14:01:10
【问题描述】:

Ng-click 在 ng-repeat 内部不起作用。在外面它工作。 我放了一个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>

【问题讨论】:

    标签: angularjs angularjs-ng-repeat angularjs-ng-click


    【解决方案1】:

    正如 Ven 提到的,ng-repeat 确实为循环中的每个项目创建了一个子范围。子作用域确实可以通过原型继承访问父作用域的变量和方法。令人困惑的部分是,当您进行分配时,它会向子范围添加一个新变量,而不是更新父范围上的属性。在ng-click 中,当您进行赋值调用tiggerTitle =e.name 时,它实际上向子作用域添加了一个名为triggerTitle 的新变量。 AngularJS 文档在此处称为 JavaScript Prototypal Inheritance 的部分中很好地解释了这一点。

    那么你如何解决这个问题并正确设置模型变量?

    一个快速而肮脏的解决方案是像这样使用$parent 访问父作用域。

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

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

    如果您处理嵌套模板或嵌套 ng-repeats,使用 $parent 可能会导致问题。更好的解决方案可能是向控制器的作用域添加一个函数,该函数返回对控制器作用域的引用。如前所述,子作用域有权调用父函数,因此可以引用控制器的作用域。

    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

    【讨论】:

    • 应该标记为正确答案。但解释应简化为总共 3 行。 ng-repeat 创建新范围。如果您尝试通过 ng-click 从 ng-repeat 访问 $scope,则需要在该元素上使用 $parent。感谢您的指导
    • 认为最好的解决方案是“controllerAs”
    【解决方案2】:

    因为ng-repeat 创建了一个新范围。

    这个问题已经回答了很多次了,因为细微差别有点难以理解,尤其是如果你对 js 的原型继承一​​无所知:https://github.com/angular/angular.js/wiki/Understanding-Scopes

    编辑:看来这个答案很有争议。需要明确一点——这就是 JS 的工作方式。在了解 JS 的工作原理之前,您真的不应该尝试学习 Angular。 但是,链接似乎确实错过了

    所以,这里有一个例子说明 JS 在这种情况下是如何工作的:

    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!
    

    那么,我们该如何解决呢?

    好吧,我们可以“强制”自己通过继承链——因此我们将确保我们始终访问正确的对象,无论是访问值还是修改它。

    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
    

    【讨论】:

    • 因未解决 ng-click 在 ng-repeat 中不起作用的问题而被否决。
    • 我知道尝试在线查找工作的 AngularJS 示例是我遇到的最困难的编程问题之一。这个框架很棒,但它是一个谜,它的文档还有一些不足之处。
    • 提出问题而不是仅仅说“BAH DOWNVOTED YOUR ANSWER SUCKS”通常会更好;)。现在,停止开玩笑,我没有提供固定代码,因为这是作者需要理解的内容。这在使用 Angular 时非常重要,如果您不牢记该规则,您将花时间调试因不使用点而引起的问题。
    • 这个答案只不过是“RTFM”。 OP“需要理解它”的借口并没有削减它。
    • 唉,原来如此。如果你还没有准备好学习你使用的语言的一部分,那么无论如何你都会遇到麻烦。
    【解决方案3】:

    而不是这个:

    <li ng-repeat="e in events">
      <a ng-click="triggerTitle=e.name; triggerEvent = e.action;">{{e.action}} {{e.name}}</a>
    </li>
    

    这样做:

    <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 创建一个新作用域,您可以使用$parentng-repeat 块内访问父作用域。

    【讨论】:

      【解决方案4】:

      这里我们可以使用 $parent 以便我们可以访问 ng-repeat 之外的代码。

      HTML代码

      <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 代码

      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'}]
      

      }

      你可以在这里测试http://jsfiddle.net/xVZEX/96/

      【讨论】:

        【解决方案5】:

        这个工程

        <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】:

        我在网上冲浪了很长时间,寻找 ng-repeat 在其中创建自己的范围的问题的答案。当您更改 ng-repeat 中的变量时,视图不会在文档中的其他任何地方更新。

        最后我找到的解决方案是一个词,没有人告诉你。

        它是 $parent。在变量名之前,它将在全局范围内更改其值。

        所以

        ng-click="entryID=1"
        变成
        ng-click="$parent.entryID=1"

        【讨论】:

          【解决方案7】:

          使用这个

          <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>
          

          我将 ng-click 转换为 ng:click 并开始工作,我还没有找到原因,只是快速发布分享。

          【讨论】:

            【解决方案8】:

            使用带有“as”关键字的控制器。

            检查控制器上 angularjs 上的documentation

            对于上述问题:

            <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>
            

            这会将属性和函数附加到控制器的范围内。

            【讨论】:

              最近更新 更多