Javascript-форум (https://javascript.ru/forum/)
-   Angular.js (https://javascript.ru/forum/angular/)
-   -   $digest() iterations reached. (https://javascript.ru/forum/angular/48205-%24digest-iterations-reached.html)

Yetty 24.06.2014 18:43

$digest() iterations reached.
 
Пытаюсь разобраться с angular.

<ul>
  <li ng-repeat='a in [{q:1, w: [11,22]},{q:2, w: [33,44]}]'>
    {{a.q}}
    <ul>
      <li ng-repeat='b in a.w'>
        {{b}}
      </li>
    </ul>
  </li>
</ul>


В результате выпадает ошибка
"Error: 10 $digest() iterations reached. Aborting!
Watchers fired in the last 5 iterations:...


Данная ошибка гуглится, но как решить свою простую задачу понять не могу. Разъясните, в чём проблема?

a.malitsky 24.06.2014 19:14

вынес перебираемый массив в скоуп и всё ок. Ng repeat для a in arr. Может Ангулар как-то парсит этот синтаксис в темплейте (конкретных идей нет).

рони 24.06.2014 20:13

:-?
<!DOCTYPE HTML>
<html lang="en" ng-app>
<head>
    <title>Hello World</title>
    <script src="http://code.angularjs.org/1.2.18/angular.min.js" ></script>

</head>
<body>
    <ul ng-controller="Test">
  <li ng-repeat='a in myArrayOfObjects'>
    {{a.q}}
    <ul>
      <li ng-repeat='b in a.w'>
         {{b}}
      </li>
    </ul>
  </li>
</ul>
    <script type="text/javascript">
        function Test($scope)
        {    $scope.myArrayOfObjects    = [{q:1, w: [11,22]},{q:2, w: [33,44]}]

        }
    </script>
</body>
</html>

a.malitsky 24.06.2014 20:34

http://jsfiddle.net/amalitsky/b66Jv/1/

рони 25.06.2014 01:05

:)
<!DOCTYPE HTML>
<html lang="en" ng-app>
<head>
    <title>test</title>
    <script src="http://code.angularjs.org/1.2.18/angular.min.js" ></script>
</head>
<body>
<ul ng-init='test=[{q:1, w: [11,22]},{q:2, w: [33,44]}]'>
  <li ng-repeat='a in test'>
    {{a.q}}
    <ul>
      <li ng-repeat='b in a.w'>
        {{b}}
      </li>
    </ul>
  </li>
</ul>
</body>
</html>

a.malitsky 25.06.2014 01:10

не для этого примера, а вообще стоит помнить:
The only appropriate use of ngInit is for aliasing special properties of ngRepeat, as seen in the demo below. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
Встречаю в коде частенько.

Yetty 25.06.2014 12:21

Основную причину я всё равно не понял.

Приведу другой пример. Скажем, что мне список нужно обновить по некоторому событию от другого фреймворка.

Вот этот код не работает:
<!DOCTYPE HTML>
<html lang="en" ng-app>
<head>
    <title>Test</title>
    <script type="text/javascript" src="js/angular/angular.min.js"></script>
    <script type="text/javascript">
        var MyEvent;
        var GenerateEvent = function () {
            MyEvent();
        };

        function FeaturesListCtrl($scope) {
            $scope.GetSecondLevel = function () {
                return [
                    { b: '11' },
                    { b: '22' }
                ];
            }

            var OnEvent = function () {
                $scope.firstLevel = [
                    { a: '1' }, 
                    { a: '2' }, 
                    { a: '3' }
                ];
                
//                $scope.secondLevel = [
//                    { b: '11' },
//                    { b: '22' }
//                ]
                
                $scope.$apply();
            }

            MyEvent = OnEvent;
        }
    </script>
</head>

<body>
    <input type="button" onclick="GenerateEvent()" value="Event">
    <div ng-controller='FeaturesListCtrl'>
        <ul>
            <li ng-repeat='level1 in firstLevel'>
                {{level1.a}}
                <ul>
                    <!--li ng-repeat='level2 in secondLevel'-->
                    <li ng-repeat='level2 in GetSecondLevel()'>
                        {{level2.b}}
                    </li>
                </ul>
            </li>
        </ul>
    </div>

</body>

</html>


А вот этот работает:
<!DOCTYPE HTML>
<html lang="en" ng-app>

<head>
    <title>Test</title>
    <script type="text/javascript" src="js/angular/angular.min.js"></script>
    <script type="text/javascript">
        var MyEvent;
        var GenerateEvent = function () {
            MyEvent();
        };

        function FeaturesListCtrl($scope) {
//            $scope.GetSecondLevel = function () {
//                return [
//                    { b: '11' },
//                    { b: '22' }
//                ];
//            }

            var OnEvent = function () {
                $scope.firstLevel = [
                    { a: '1' }, 
                    { a: '2' }, 
                    { a: '3' }
                ];
                
                $scope.secondLevel = [
                    { b: '11' },
                    { b: '22' }
                ]
                
                $scope.$apply();
            }

            MyEvent = OnEvent;
        }
    </script>
</head>

<body>
    <input type="button" onclick="GenerateEvent()" value="Event">

    <div ng-controller='FeaturesListCtrl'>
        <ul>
            <li ng-repeat='level1 in firstLevel'>
                {{level1.a}}
                <ul>
                    <li ng-repeat='level2 in secondLevel'>
                    <!--li ng-repeat='level2 in GetSecondLevel()'-->
                        {{level2.b}}
                    </li>
                </ul>
            </li>
        </ul>
    </div>
</body>
</html>


Мне необходимо понять как работать по первому варианту, так как функция может возвращать данные в зависимости от некоторых входных параметров...

Но в чём между первым и вторым разница для angular я не понимаю.

Yetty 25.06.2014 12:27

Даже ещё проще (не работает)
<!DOCTYPE HTML>
<html lang="en" ng-app>

<head>
    <title>Test</title>
    <script type="text/javascript" src="js/angular/angular.min.js"></script>
    <script type="text/javascript">
        function FeaturesListCtrl($scope) {
            $scope.firstLevel = [
                { a: '1' }, 
                { a: '2' }, 
                { a: '3' }
            ];

            $scope.GetSecondLevel = function () {
                return [
                    { b: '11' },
                    { b: '22' }
                ];
            }
        }
    </script>
</head>

<body>
    <input type="button" onclick="GenerateEvent()" value="Event">

    <div ng-controller='FeaturesListCtrl'>
        <ul>
            <li ng-repeat='level1 in firstLevel'>
                {{level1.a}}
                <ul>
                    <li ng-repeat='level2 in GetSecondLevel()'>
                        {{level2.b}}
                    </li>
                </ul>
            </li>
        </ul>
    </div>

</body>

</html>

Yetty 25.06.2014 13:20

Вот этот вариант работает и подходит, но он вырвиглазненько выглядит.
В случае двух уровней ещё более менее, но если три и более уровней, там с ума сойдёшь...
<!DOCTYPE HTML>
<html lang="en" ng-app>

<head>
    <title>Test</title>
    <script type="text/javascript" src="js/angular/angular.min.js"></script>
    <script type="text/javascript" src="js/jquery/jquery-1.10.2.js"></script>
    
    <script type="text/javascript">
        function FeaturesListCtrl($scope) {
            var GetL2 = function(l1){
                rtn = []
                $.each(l1, function(i, n){
                    rtn.push([
                        n.a + (i + 1).toString() + '_qwe',
                        n.a + (i + 1).toString() + '_asd'
                    ]);
                });
                return rtn;
            }
            
            $scope.l1 = [
                { a: '1' }, 
                { a: '2' }
            ];
            
            $scope.l2 = GetL2($scope.l1);

            
        }
    </script>
</head>

<body>
    <div ng-controller='FeaturesListCtrl'>
        <ul>
            <li ng-repeat='level1 in l1' ng-init="outerIndex = $index">
                {{level1.a}}
                <ul>
                    <li ng-repeat='level2 in l2[outerIndex]'>
                        {{level2}}
                    </li>
                </ul>
            </li>
        </ul>
    </div>

</body>

</html>


Есть другие варианты?

a.malitsky 25.06.2014 18:51

не понятно зачем пытаться ng-repeat подкладывать функцию, когда он ждёт массив или объект. Три секунды поиска.

По событию меняем массив, если "внутри ангулара", то список перерендерится, если вне, то добавляем apply. Вроде такие примеры у тебя работают. В чём вопрос?

рони 25.06.2014 20:35

Цитата:

Сообщение от a.malitsky
По событию меняем массив, если "внутри ангулара", то список перерендерится, если вне, то добавляем apply.

не могли бы вы привести рабочий пример если вам не трудно.

a.malitsky 25.06.2014 20:49

http://jsfiddle.net/hLTpn/

рони 25.06.2014 21:36

a.malitsky,
спасибо а немогли бы вы пояснить эту строку $scope.Math = Math; что она делает зачем нужна?

a.malitsky 25.06.2014 22:58

она нужна чтобы в ng-click увидел Math :) иначе его там не будет, почему так - не скажу, надо искать инфу. Просто стоит помнить что в "template-embedded" expression могут быть неожиданные сложности и не удивляться. Я пока пример этот не написал, с ними не сталкивался, так как в основном там лежит function invocation.

nerv_ 26.06.2014 11:34

https://docs.angularjs.org/guide/expression


Часовой пояс GMT +3, время: 00:24.