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. Вроде такие примеры у тебя работают. В чём вопрос?


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