web-dev-qa-db-fra.com

Ng-click ne fonctionne pas dans ng-repeat

Ng-click ne fonctionne pas à l'intérieur de ng-repeat. Dehors ça marche . J'ai mis un violon ici

<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>
26
Alexandru Rada

Comme Ven l'a mentionné, ng-repeat crée une étendue enfant pour chaque élément de la boucle. Les étendues enfants ont accès aux variables et méthodes de la portée parent via l'héritage de prototypes. La partie déroutante est que lorsque vous effectuez une affectation, il ajoute une nouvelle variable à la portée enfant plutôt que de mettre à jour la propriété sur la portée parente. Dans ng-click, lorsque vous effectuez un appel d'affectation tiggerTitle =e.name, il ajoute en fait une nouvelle variable appelée triggerTitle à la portée de l'enfant. La documentation AngularJS explique cela dans la section Héritage prototypique JavaScript .

Alors, comment vous en sortir et définir correctement la variable de modèle? 

Une solution rapide et incorrecte consiste à accéder à la portée parent à l'aide de $parent comme suit.

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

Cliquez pour afficher une version de travail de votre Fiddle à l'aide de la solution $ parent.

L'utilisation de $parent peut entraîner des problèmes si vous traitez avec des modèles imbriqués ou des répétitions imbriquées imbriquées. Une meilleure solution peut être d’ajouter une fonction à la portée du contrôleur qui renvoie une référence à la portée du contrôleur. Comme mentionné précédemment, les étendues enfants ont le droit d'appeler les fonctions parent et peuvent donc référencer l'étendue du contrôleur. 

function MyCtrl($scope) {
    $scope.getMyCtrlScope = function() {
         return $scope;   
    }
 ...

<a ng-click="getMyCtrlScope().triggerTitle=e.name;getMyCtrlScope().triggerEvent = ...

Cliquez pour voir une version de travail de votre Fiddle en utilisant la meilleure méthode

51
James Lawruk

Parce que ng-repeat crée une nouvelle portée.

Cela a été répondu à maintes reprises, car la nuance est un peu difficile à comprendre, surtout si vous ne connaissez pas tout l'héritage prototypal de js: https://github.com/angular/angular.js/wiki/Understanding Portées

EDIT: il semble que cette réponse est très controversée. Juste pour être clair - c'est comme ça que JS fonctionne. Vous ne devriez vraiment pas essayer d'apprendre Angular avant de comprendre comment fonctionne JS . Cependant, le lien semble manquer 

Alors, voici un exemple sur le fonctionnement de JS dans ce cas:

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!

Alors, comment pouvons-nous contourner cela?

Eh bien, nous pouvons nous "forcer" à suivre la chaîne de l'héritage - et nous nous assurerons donc que nous avons toujours accès au bon objet, que ce soit pour accéder à la valeur ou pour le modifier.

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

Au lieu de cela:

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

Faites juste ceci:

<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 crée une nouvelle portée, vous pouvez utiliser $parent pour accéder à la portée parente à l'intérieur du bloc ng-repeat.

6
Iain Collins

Ici, nous pouvons utiliser $ parent pour pouvoir accéder au code en dehors de ng-repeat.

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

Code Js angulaire 

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

}

vous pouvez le tester ici http://jsfiddle.net/xVZEX/96/

3
Harpreet Singh

Cela marche 

<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>
1
Uday Gowda

J'ai longtemps surfé sur Internet à la recherche d'une réponse au problème de ng-repeat en créant sa propre portée. Lorsque vous modifiez une variable dans ng-repeat, les vues ne sont pas mises à jour ailleurs dans le document. 

Et finalement, la solution que j'ai trouvée était un mot, et personne ne vous l'a dit.

C'est $ parent. avant le nom de la variable et sa valeur changera dans la portée globale.

Alors 

ng-click="entryID=1"
devient
ng-click="$parent.entryID=1"

0
Rohan Hussain

utilisez ceci

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

J'ai converti ng-click en ng: click et ça a commencé à fonctionner, je n'ai pas encore trouvé le motif, je l'ai posté rapidement pour le partage.

0
Hitesh Joshi

Utilisez des contrôleurs avec le mot clé 'as'.

Vérifiez la documentation sur angularjs sur les contrôleurs.

Pour la question ci-dessus:

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

Cela va attacher les propriétés et les fonctions à la portée du contrôleur.

0
Gerrard8