ng-repeat를 사용하여 함수에서 반환 한 항목을 반복하는 방법은 무엇입니까?


114

반복적으로 div를 만들고 싶습니다. 항목은 함수에서 반환하는 개체입니다. 그러나 다음 코드는 오류를보고합니다. 10 $ digest () 반복에 도달했습니다. 중단! jsfiddle은 여기에 있습니다 : http://jsfiddle.net/BraveOstrich/awnqm/

<body ng-app>
  <div ng-repeat="entity in getEntities()">
    Hello {{entity.id}}!
  </div>
</body>

답변:


195

짧은 대답 : 정말로 그러한 기능이 필요합니까 아니면 속성을 사용할 수 있습니까? http://jsfiddle.net/awnqm/1/

긴 대답

단순화를 위해 객체 배열에 대한 ngRepeat의 경우 만 설명합니다. 또한 세부 사항은 생략하겠습니다.

AngularJS는 변경 사항을 감지하기 위해 더티 검사 를 사용합니다 . 응용 프로그램이 시작되면 그것은 실행 $digest을 위해 $rootScope. 범위의 계층에$digest 대해 깊이 우선 순회를 수행 합니다 . 모든 범위에는 시계 목록이 있습니다. 각 시계에는 마지막 값이 있습니다 (처음에는 initWatchVal). 모든 시계에 대한 각 범위에 대해 $digest실행하고 현재 값 ( watch.get(scope))을 가져 와서 watch.last. 현재 값이 watch.last(항상 첫 번째 비교를 위해) 같지 않으면로 $digest설정 dirty됩니다 true. 경우 모든 범위를 처리 할 때 dirty == true $digest의 또 다른 깊이 우선 탐색을 시작합니다 $rootScope. $digestdirty == false 또는 순회 횟수 == 10 일 때 종료됩니다. 후자의 경우 "10 $ digest () 반복에 도달했습니다."오류가 발생합니다. 기록됩니다.

이제 ngRepeat. 각 watch.get호출에 대해 getEntities캐시 ( HashQueueMapby hashKey) 에 추가 정보와 함께 컬렉션 (값 반환)의 개체를 저장합니다 . 모든 watch.get호출 ngRepeat에 대해 hashKey캐시에서 객체를 가져 오려고 합니다. 캐시에 존재하지 않는 경우 캐시에 ngRepeat저장하고, 새 범위를 생성하고, 객체를 배치하고, DOM 요소를 생성하는 등의 작업을 수행 합니다.

이제 hashKey. 일반적으로에서 hashKey생성 한 고유 번호 nextUid()입니다. 그러나 그것은 기능 일 수 있습니다 . hashKey나중에 사용하기 위해 생성 후 객체에 저장됩니다.

예제에서 오류가 발생하는 이유 : 함수는 getEntities()항상 새 객체로 배열을 반환합니다. 이 개체는 캐시에 hashKey없으며 존재하지 않습니다 ngRepeat. 따라서 ngRepeat각각에 watch.get대한 새 시계를 사용하여 새 범위를 생성합니다 {{entity.id}}. 이 시계는 처음 watch.getwatch.last == initWatchVal. 그래서 watch.get() != watch.last. 그래서 $digest새로운 횡단을 시작합니다. 그래서 ngRepeat새로운 시계로 새로운 범위를 만듭니다. 그래서 ... 10 번의 트래버스 후에는 오류가 발생합니다.

고칠 수있는 방법

  1. 모든 getEntities()호출 에서 새 개체를 만들지 마십시오 .
  2. 새 개체를 만들어야하는 경우 hashKey메서드를 추가 할 수 있습니다 . 예제는 이 주제 를 참조하십시오 .

AngularJS 내부를 아는 사람들이 내가 뭔가 잘못되면 나를 바로 잡기를 바랍니다.


4
+1 감사합니다. 나는 같은 문제가 있었고 정적 속성을 사용할 수 없었습니다. $$ hashKey는 수동 IMO의 ngRepeat 페이지에 실제로 문서화되어야합니다.
Michael Moussa

이것에 영향을 미친 1.1.3에서 1.1.4로 변경된 것이 무엇인지 아십니까? 1.1.4 이전에는 실제로 작동했습니다. 그것에 대한 변경 로그에는 아무것도 없으며 차이점이 무엇인지 추론 할 수 없습니다. 현재 동작이 의미가 있습니다.
m59

또한 할 수 있다면 이것을 확인하십시오 : stackoverflow.com/questions/20933261/… 내 대답이 갈 길인지 모르겠습니다 ..
m59

2
따라서 권장 사항을 따르면 다음과 Do not create new objects on every getEntities() call.같이 매우 쉽게 수정할 수 있습니다.<div ng-repeat="entity in entities = (entities || getEntities())">
przno

2
내 이전 의견의 솔루션은 getEntities()항상 동일한 배열을 반환하는 경우에 작동 합니다. 배열이 변경되면 다음에서 얻을 수 없습니다ng-repeat
przno

44

반복 외부에서 배열 초기화

<body ng-app>
   <div ng-init="entities = getEntities()">
       <div ng-repeat="entity in entities">
           Hello {{entity.id}}!
       </div>
   </div>
</body>

8
getEntities()프로그램의 수명주기에서 다른 것을 반환 하면 작동하지 않습니다 . 말, 예를 들어, 그 getEntities()트리거 $http.get. 최종적으로 해결되면 (AJAX 호출을 수행함) entities이미 초기화됩니다.
Nighto

3
각도 문서에서The only appropriate use of ngInit is for aliasing special properties of ngRepeat. Besides this case, you should use controllers rather than ngInit to initialize values on a scope.
Blowsie

요점은 어떤 수단 으로든 "반복 외부에서 배열을 초기화"하는 것입니다 ... 그리고 @Nighto 약속에 대한 좋은 전화
Mwayi

15

여기에 보고되었으며 다음 과 같은 응답을 받았습니다.

getter는 멱 등성이 아니며 모델을 변경합니다 (호출 될 때마다 새 배열을 생성 함). 이것은 모델이 결국 안정화되기를 바라면서 angular가 계속 호출하도록 강요하지만 결코 그렇게하지 않습니다. angular는 포기하고 예외를 던집니다.

게터가 반환하는 값은 동일하지만 동일하지는 않으며 그게 문제입니다.

메인 컨트롤러 외부로 어레이를 이동하면이 동작이 사라지는 것을 볼 수 있습니다.

var array = [{id:'angularjs'}];
function Main($scope) {
    $scope.getEntities = function(){return array;};
};

이제 매번 동일한 객체를 반환하기 때문입니다. 함수 대신 범위의 속성을 사용하려면 모델을 다시 설계해야 할 수 있습니다.

컨트롤러 메서드의 결과를 속성에 할당하고 이에 대해 ng : repeat를 수행하여 문제를 해결했습니다.


함수에 각 반복마다 매개 변수가 변경되는 경우 속성을 사용하는 것이 유일한 방법 일 수 있습니다.
Stephane

7

@przno 주석을 기반으로

<body ng-app>
  <div ng-repeat="item in t = angular.equals(t, getEntities()) ? t : getEntities()">
    Hello {{item.id}}!
  </div>
</body>

BTW 두 번째 솔루션 @Artem Andreev는 Angular 1.1.4 이상에서 작동하지 않는 반면 첫 번째 솔루션은 문제를 해결하지 않는다고 제안합니다. 그래서 지금은 이것이 기능상의 단점이없는 덜 뾰족한 솔루션입니다.


item.id를 의미합니까? entity.id가 의미하는 경우 설명해 주시겠습니까? 감사합니다!
Gerfried

그래, 너가 맞아. Item.idb. 감사합니다
Agat
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.