Ng-click не работает внутри ng-repeat

Ng-click не работает изнутри ng-repeat. Снаружи работает. Я поместил сюда скрипку

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

person Alexandru R    schedule 24.05.2013    source источник


Ответы (8)


Как упоминал Вен, ng-repeat создает дочернюю область для каждого элемента в цикле. Дочерние области имеют доступ к переменным и методам родительской области через прототипное наследование. Запутанная часть заключается в том, что когда вы выполняете назначение, оно добавляет новую переменную в дочернюю область, а не обновляет свойство в родительской области. В ng-click, когда вы делаете вызов присваивания tiggerTitle =e.name, он фактически добавляет новую переменную с именем triggerTitle в дочернюю область. Документация по AngularJS хорошо объясняет это в разделе здесь под названием JavaScript Prototypal. Наследование.

Как же обойти это и правильно установить переменную модели?

Быстрое и грязное решение - получить доступ к родительской области, используя $parent вот так.

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

Нажмите, чтобы просмотреть рабочую версию Fiddle, использующую решение $parent.

Использование $parent может вызвать проблемы, если вы имеете дело с вложенными шаблонами или вложенными повторами ng. Лучшим решением может быть добавление функции в область действия контроллера, которая возвращает ссылку на область действия контроллера. Как уже упоминалось, дочерние области имеют доступ для вызова родительских функций и, таким образом, могут ссылаться на область действия контроллера.

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

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

Нажмите, чтобы увидеть рабочую версию Fiddle с использованием лучшего метода

person James Lawruk    schedule 25.09.2014
comment
Должен быть отмечен как правильный ответ. Но объяснение должно быть упрощено до 3 строк. ng-repeat создает новую область. если вы пытаетесь получить доступ к $scope из ng-repeat с помощью ng-click, вам нужно использовать $parent для этого элемента. хотя спасибо за направление - person Linial; 30.10.2014
comment
Думаю, лучшим решением будет контроллер. - person Lyubimov Roman; 01.02.2016

Потому что ng-repeat создает новую область.

На этот вопрос отвечали много раз, потому что нюанс немного сложно понять, особенно если вы не знаете всего о прототипном наследовании js: https://github.com/angular/angular.js/wiki/Understanding-Scopes

РЕДАКТИРОВАТЬ: кажется, этот ответ очень спорный. Просто для ясности — так работает JS. Вы действительно не должны пытаться изучать Angular, пока не поймете, как работает JS. Тем не менее, ссылка, кажется, отсутствует

Итак, вот пример того, как 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
person Ven    schedule 24.05.2013
comment
Проголосовали за то, что не решили проблему, когда ng-click не работает внутри ng-repeat. - person Sarah Vessels; 15.08.2013
comment
Я понимаю, что попытка найти работающие примеры AngularJS в Интернете была одной из самых сложных проблем программирования, с которыми я сталкивался. Этот фреймворк прекрасен, но остается загадкой, а его документация оставляет желать лучшего. - person Sarah Vessels; 20.11.2013
comment
Обычно лучше задавать вопросы, а не просто говорить, что БАХ ЗАНИМАЕТ ВАШ ОТВЕТ ОТСТОЙ ;). Теперь, чтобы прекратить шутить, я не предоставил фиксированный код, потому что это то, что должно быть понято автором. Это очень важно при работе с Angular, и если вы не знаете это правило наизусть, вы потратите время на отладку проблем, возникающих из-за того, что вы не используете точку. - person Ven; 21.11.2013
comment
Кроме того, я согласен с тем, что документация иногда не очень описательная, но там есть много примеров и очень активное сообщество. - person Ven; 21.11.2013
comment
Этот ответ немного больше, чем RTFM. Оправдание, что ОП должен понять это, не работает. - person Tony Ennis; 16.08.2014
comment
Увы, это так. Если вы не готовы учить части языка, которым пользуетесь, у вас все равно проблемы. - person Ven; 17.08.2014
comment
Хороший случай дополнительной косвенности, решающий все проблемы. +1 - person rightfold; 16.06.2015
comment
На самом деле это не дает ответа на простой и вполне разумный вопрос и вводит в заблуждение. Scope в AngularJS работает таким образом по замыслу, но в равной степени может и не работать. - person Iain Collins; 26.08.2015
comment
@IainCollins Я не понимаю, что ты говоришь. - person Ven; 26.08.2015
comment
Немного опоздал на вечеринку, но это действительно нужно снять. Вы могли бы объединить пример области JS с предоставленным решением проблемы NG-Click/Repeater. Это был бы отличный пост. - person snowYetis; 03.05.2016
comment
Я уверен, что вы можете сделать вывод, что изменение имени переменной везде (или имени свойства) не изменит поведение :-). - person Ven; 04.05.2016

Вместо этого:

<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 создает новую область, вы можете использовать $parent для доступа к родительской области внутри блока ng-repeat.

person Iain Collins    schedule 26.08.2015

Здесь мы можем использовать $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 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'}]

}

вы можете протестировать его здесь http://jsfiddle.net/xVZEX/96/

person Harpreet Singh    schedule 15.10.2016

Это работает

<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>
person Uday Gowda    schedule 25.10.2015
comment
Пожалуйста, опишите свой ответ, а не просто вставляйте блок кода. Это должно помочь кому-то понять, что (если) они сделали неправильно или упустили. - person Sjon; 25.10.2015

Я так долго бродил по Интернету в поисках ответа на проблему ng-repeat, создающего в нем свою область видимости. Когда вы изменяете переменную внутри ng-repeat, представления не обновляются где-либо еще в документе.

И, наконец, решение, которое я нашел, было одним словом, и никто вам этого не сказал.

Это $родитель. перед именем переменной, и она изменит свое значение в глобальной области видимости.

So

ng-click="entryID=1"
становится
ng-click="$parent.entryID=1"

person Rohan Hussain    schedule 29.05.2018

использовать это

<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, и он начал работать, я еще не нашел причину, просто быстро опубликовал, чтобы поделиться.

person Hitesh Joshi    schedule 27.08.2013

Используйте контроллеры с ключевым словом as.

Ознакомьтесь с документацией по angularjs на контроллерах.

По вышеуказанному вопросу:

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

Это прикрепит свойства и функции к области действия контроллера.

person Gerrard8    schedule 25.03.2015