ng-repeat finish 이벤트


207

테이블이있는 div를 대상으로하는 jQuery 함수를 호출하고 싶습니다. 해당 테이블은로 채워집니다 ng-repeat.

내가 전화하면

$(document).ready()

결과가 없습니다.

또한

$scope.$on('$viewContentLoaded', myFunc);

도움이되지 않습니다.

ng-repeat 채우기가 완료된 직후 기능을 실행할 수있는 방법이 있습니까? custom 사용에 대한 조언을 읽었 directive지만 ng-repeat 및 div와 함께 사용하는 방법에 대한 실마리는 없습니다 ...

답변:


241

실제로 지시어를 사용해야하며 ng-Repeat 루프의 끝에 연결된 이벤트가 없습니다 (각 요소는 개별적으로 구성되며 자체 이벤트가 있기 때문에). 그러나 a) 지시문을 사용하는 것이 필요할 수 있습니다. b) "on ngRepeat finished"이벤트를 만드는 데 사용할 수있는 ng-Repeat 특정 속성이 몇 가지 있습니다.

특히, 전체 테이블에 이벤트를 스타일 지정 / 추가하는 것이 모든 ngRepeat 요소를 포함하는 지시문을 사용하여 수행 할 수 있습니다. 반면에 각 요소를 구체적으로 지정하려면 ngRepeat 내에서 지시문을 사용하면 각 요소가 작성된 후 각 요소에 대해 작동합니다.

그런 다음, 거기에있는 $index, $first, $middle$last속성은 트리거 이벤트에 사용할 수 있습니다. 따라서이 HTML의 경우 :

<div ng-controller="Ctrl" my-main-directive>
  <div ng-repeat="thing in things" my-repeat-directive>
    thing {{thing}}
  </div>
</div>

다음과 같은 지시문을 사용할 수 있습니다.

angular.module('myApp', [])
.directive('myRepeatDirective', function() {
  return function(scope, element, attrs) {
    angular.element(element).css('color','blue');
    if (scope.$last){
      window.alert("im the last!");
    }
  };
})
.directive('myMainDirective', function() {
  return function(scope, element, attrs) {
    angular.element(element).css('border','5px solid red');
  };
});

Plunker 에서 실제로 작동하는 것을 보십시오 . 그것이 도움이되기를 바랍니다!


나는 할 수있다 myMainDirective'코드는 루프의 종료 후 실행 s는? 부모 div의 스크롤 막대를 업데이트해야합니다.
ChruS

2
물론이야! "window.alert"를 이벤트 발생 함수로 변경하고 기본 지시문으로 잡으십시오. 예를 들어 de Plunker를 업데이트했습니다.
Tiago Roldão

9
jQuery 라이브러리를 먼저 (앵귤러 이전에) 포함하는 것이 좋습니다. 그러면 모든 Angular 요소가 jqLite 대신 jQuery로 래핑됩니다. 그런 다음 angular.element (element) .css () 및 $ (element) .children (). css () 대신 element.css () 및 element.children (). css ()를 작성할 수 있습니다. groups.google.com/d/msg/angular/6A3Skwm59Z4/oJ0WhKGAFK0J
Mark Rajcok

11
Any1은 ngRepeat 지시문에서 후속 렌더링 에이 기능을 사용하는 방법을 알고 있습니까? 즉 : 링크
RavenHursT

1
이것은 모든 각도 지시문의 명명 규칙입니다. docs.angularjs.org/guide/directive#normalization
Tiago Roldão을

68

루프가 끝날 때 일부 코드를 실행하려면 추가 이벤트 처리가 필요하지 않은 약간 간단한 변형이 있습니다.

<div ng-controller="Ctrl">
  <div class="thing" ng-repeat="thing in things" my-post-repeat-directive>
    thing {{thing}}
  </div>
</div>
function Ctrl($scope) {
  $scope.things = [
    'A', 'B', 'C'  
  ];
}

angular.module('myApp', [])
.directive('myPostRepeatDirective', function() {
  return function(scope, element, attrs) {
    if (scope.$last){
      // iteration is complete, do whatever post-processing
      // is necessary
      element.parent().css('border', '1px solid black');
    }
  };
});

라이브 데모를보십시오.


컨트롤러를 구문으로 사용하면 이것이 작동합니까? 부디? 그렇지 않으면 컨트롤러와 작동하는 다른 방법이 있습니까?
Dan Nguyen

63

지시어를 만들 필요는 없습니다. 특히 ng-repeat 완전한 이벤트 .

ng-init 당신을 위해 마술을 않습니다.

  <div ng-repeat="thing in things" ng-init="$last && finished()">

$last것을 확인한다finished 마지막 요소는 DOM에 렌더링 된 경우에만 트리거됩니다.

만드는 것을 잊지 마세요 $scope.finished이벤트 .

행복한 코딩 !!

편집 : 2016 년 10 월 23 일

finished배열에 항목이 없을 때 함수 를 호출하려는 경우 다음 해결 방법을 사용할 수 있습니다

<div style="display:none" ng-init="things.length < 1 && finished()"></div>
//or
<div ng-if="things.length > 0" ng-init="finished()"></div>

위의 라인을 상단에 추가하십시오. ng-repeat요소 . 배열에 값이 없는지 확인하고 그에 따라 함수를 호출합니다.

예 :

<div ng-if="things.length > 0" ng-init="finished()"></div>
<div ng-repeat="thing in things" ng-init="$last && finished()">

"things"가 빈 배열로 판명되면 어떻게합니까?
Frane Poljak

1
@FranePoljak 답변에 솔루션을 추가했습니다.
Vikas Bansal

1
빈 배열의 경우 컨트롤러에서 처리하십시오.
JSAddict

Vikas Bansal 답변 수정 : // 배열에 값이 없는지 확인하고 그에 따라 함수를 호출하려면 첫 번째 div를 사용하십시오. <div ng-if = "! things.length"ng-hide = "true"ng-init = "finished ()"> </ div> <div ng-repeat = "사물"ng-init = "$ last && finished () ">
Alex Teslenko

41

다음은 true 일 때 지정된 함수를 호출하는 반복 완료 지시문입니다. 렌더링 된 요소에서 툴팁을 초기화하는 것과 같이 DOM 조작을 수행하기 전에 호출 된 함수가 interval = 0과 함께 $ timeout을 사용해야한다는 것을 알았습니다. jsFiddle : http://jsfiddle.net/tQw6w/

$ scope.layoutDone에서 $ timeout 줄을 주석 처리하고 "NOT CORRECT!"를 주석 해제하십시오. 툴팁의 차이점을 확인하십시오.

<ul>
    <li ng-repeat="feed in feedList" repeat-done="layoutDone()" ng-cloak>
    <a href="{{feed}}" title="view at {{feed | hostName}}" data-toggle="tooltip">{{feed | strip_http}}</a>
    </li>
</ul>

JS :

angular.module('Repeat_Demo', [])

    .directive('repeatDone', function() {
        return function(scope, element, attrs) {
            if (scope.$last) { // all are rendered
                scope.$eval(attrs.repeatDone);
            }
        }
    })

    .filter('strip_http', function() {
        return function(str) {
            var http = "http://";
            return (str.indexOf(http) == 0) ? str.substr(http.length) : str;
        }
    })

    .filter('hostName', function() {
        return function(str) {
            var urlParser = document.createElement('a');
            urlParser.href = str;
            return urlParser.hostname;
        }
    })

    .controller('AppCtrl', function($scope, $timeout) {

        $scope.feedList = [
            'http://feeds.feedburner.com/TEDTalks_video',
            'http://feeds.nationalgeographic.com/ng/photography/photo-of-the-day/',
            'http://sfbay.craigslist.org/eng/index.rss',
            'http://www.slate.com/blogs/trending.fulltext.all.10.rss',
            'http://feeds.current.com/homepage/en_US.rss',
            'http://feeds.current.com/items/popular.rss',
            'http://www.nytimes.com/services/xml/rss/nyt/HomePage.xml'
        ];

        $scope.layoutDone = function() {
            //$('a[data-toggle="tooltip"]').tooltip(); // NOT CORRECT!
            $timeout(function() { $('a[data-toggle="tooltip"]').tooltip(); }, 0); // wait...
        }

    })

$ timeout을 사용하고 싶지 않았지만 0으로 설정할 수 있다고 말했을 때 시도해보기로 결정했습니다. 이것이 소화의 문제인지, $ timeout을 사용하지 않고 $ timeout이하는 일을 수행 할 수있는 방법이 있는지 궁금합니다.
Jameela Huq 2016

왜 이것이 작동하는지 설명해 주시겠습니까? 동적 ID에 액세스하려고하는데 지연 시간이 0이고 시간이 초과 된 후에 만 ​​작동합니다. 여러 게시물에서이 "해킹"솔루션을 보았지만 왜 작동하는지 아무도 설명하지 못했습니다.
Jin

30

여기 ng-init에는 사용자 지정 지시문이 필요없는 간단한 접근 방식이 있습니다. 그것은 페이지로드시 특정 항목으로 ng-repeated 항목의 div를 자동 스크롤 해야하는 특정 시나리오에서 나에게 효과적이었습니다. 따라서 스크롤 기능 ng-repeat은 DOM에 대한 렌더링이 완료 될 때까지 기다려야 실행 됩니다.

<div ng-controller="MyCtrl">
    <div ng-repeat="thing in things">
        thing: {{ thing }}
    </div>
    <div ng-init="fireEvent()"></div>
</div>

myModule.controller('MyCtrl', function($scope, $timeout){
    $scope.things = ['A', 'B', 'C'];

    $scope.fireEvent = function(){

        // This will only run after the ng-repeat has rendered its things to the DOM
        $timeout(function(){
            $scope.$broadcast('thingsRendered');
        }, 0);

    };
});

이것은 ng-repeat가 처음 렌더링 된 후 한 번만 호출해야하는 함수에만 유용합니다. ng-repeat 내용이 업데이트 될 때마다 함수를 호출 해야하는 경우이 스레드의 다른 답변 중 하나를 사용자 지정 지시문과 함께 사용해야합니다.


1
아름답습니다. 텍스트 상자에서 텍스트를 자동 선택하고 시간 초과로 트릭을 수행했습니다. 그렇지 않으면, 데이터 바인딩 된 model.value가 주입 될 때 {{model.value}} 텍스트가 선택된 다음 선택 해제됩니다.
JoshGough

27

Pavel의 답변을 보완 하면 더 읽기 쉽고 쉽게 이해할 수있는 것이 있습니다.

<ul>
    <li ng-repeat="item in items" 
        ng-init="$last ? doSomething() : angular.noop()">{{item}}</li>
</ul>

angular.noop처음에 거기에 있다고 생각 합니까?

장점 :

이에 대한 지시문을 작성할 필요가 없습니다 ...


20
부울 논리를 사용할 수있을 때 삼항을 사용하는 이유 :ng-init="$last && doSomething( )"
Nate Whittaker

@NateWhittaker를 읽는 것이 더 쉽습니다 (삼항 연산자보다 읽기가 어렵다는 것은 인상적입니다). 깨끗하고 이해하기 쉬운 코드를 작성하는 것이 좋습니다
Justin

21

사용자 지정 지시문이 필요하지 않고 ngInitLodash의 debounce방법을 사용하여 조금 더 간단한 접근 방식 일 수 있습니다 .

제어 장치:

$scope.items = [1, 2, 3, 4];

$scope.refresh = _.debounce(function() {
    // Debounce has timeout and prevents multiple calls, so this will be called 
    // once the iteration finishes
    console.log('we are done');
}, 0);

주형:

<ul>
    <li ng-repeat="item in items" ng-init="refresh()">{{item}}</li>
</ul>

최신 정보

삼항 연산자를 사용하는 더 간단한 순수한 AngularJS 솔루션이 있습니다.

주형:

<ul>
    <li ng-repeat="item in items" ng-init="$last ? doSomething() : null">{{item}}</li>
</ul>

알고 있음을 수 ngInit의 사용은 사전 링크 컴파일 단계 - 자녀의 지시가 처리되기 전에, 즉 표현이 호출됩니다. 이것은 여전히 ​​비동기 처리가 필요할 수 있음을 의미합니다.


이것을 작동시키기 위해서는 lodash.js가 필요하다는 것을 명심해야한다.
Jørgen Skår Fischer

디 바운스 링크 앞에 Lodash 를 추가 했습니다 . 예, 20은 메소드가 실행되기 전 지연입니다. 호출이 비동기 인 한 중요하지 않으므로 0으로 변경됩니다.
Pavel Horal

1
또한 삼항 연산자가 간단한 표현에서도 허용되기 때문에 이것에 대해 생각 ng-init="$last ? refresh() : false"하면 효과가 있습니다. 그리고 그것은 Lodash를 요구하지도 않습니다.
Pavel Horal

<div ng-repeat = "i in [1,2,4]"ng-init = "doSomething ($ last)"> </ div> $ scope.doSomething = function (lastElement) {if (lastElem) blah blah blah }
JSAddict

4

scope.$last변수를 확인 하여 트리거를 랩으로 래핑 할 때 필요할 수도 있습니다 setTimeout(someFn, 0). A setTimeout 0는 자바 스크립트에서 허용되는 기술이며 directive올바르게 실행 하는 것이 필수적이었습니다 .


나는 같은 문제를 발견했다. 백본 + 각도에서 DOM 요소에 적용된 CSS 속성 값 읽기와 같은 작업을 수행 해야하는 경우 시간 초과 해킹이없는 방법을 알 수 없었습니다.
chovy 2018 년

3

이것은 선언적 구문과 격리 범위 ( 요소 지시어를 사용하는 것이 좋습니다. 주요 차이점은 다음과 같습니다 scope.$parent.$last..

angular.module('myApp', [])
.directive('myRepeatDirective', function() {
  return {
    restrict: 'E',
    scope: {
      someAttr: '='
    },
    link: function(scope, element, attrs) {
      angular.element(element).css('color','blue');
      if (scope.$parent.$last){
        window.alert("im the last!");
      }
    }
  };
});

지시문을 요소보다 속성으로 사용하는 것이 더 좋지 않습니까? 즉 제한 : 'A'?
Tejasvi Hegde

2
요점은 선언적 구문 + 분리 범위를 표시하는 것이 었습니다 ... 예, 원하는 경우 여기에서 속성 지시문을 사용할 수 있습니다. 목적에 따라 시간과 장소가 있습니다.
JoshuaDavid

3

나는 이렇게했다.

지시문 작성

function finRepeat() {
    return function(scope, element, attrs) {
        if (scope.$last){
            // Here is where already executes the jquery
            $(document).ready(function(){
                $('.materialboxed').materialbox();
                $('.tooltipped').tooltip({delay: 50});
            });
        }
    }
}

angular
    .module("app")
    .directive("finRepeat", finRepeat);

이 ng-repeat가있는 라벨에 추가 한 후

<ul>
    <li ng-repeat="(key, value) in data" fin-repeat> {{ value }} </li>
</ul>

그리고 그 준비가 ng-repeat의 끝에서 실행될 것입니다.


3
<div ng-repeat="i in items">
        <label>{{i.Name}}</label>            
        <div ng-if="$last" ng-init="ngRepeatFinished()"></div>            
</div>

내 솔루션은 항목이 반복적으로 마지막 인 경우 함수를 호출하기 위해 div를 추가하는 것이 었습니다.


2

위의 답변은 ngRepeat이 완료 된 후 실행하는 데 필요한 코드가 각도 코드이므로 다른 답변을 추가하고 싶습니다.이 경우 위의 모든 답변은 다른 것보다 더 일반적이고 훌륭하고 간단한 솔루션을 제공합니다. 중요한 다이제스트 수명주기 단계를 살펴보면 Ben Nadel의 블로그를 인 경우 $ eval 대신 $ parse를 사용하는 것을 제외 .

그러나 내 경험상 OP 상태에서 일반적으로 finnaly 컴파일 된 DOM에서 일부 JQuery 플러그인 또는 메소드를 실행합니다.이 경우 setTimeout 함수가 푸시되기 때문에 가장 간단한 해결책은 setTimeout으로 지시문을 작성하는 것입니다. 브라우저 대기열의 끝까지 모든 것이 각도로 완료 된 직후 항상, 일반적으로 ngReapet은 부모의 postLinking 함수 후에 계속됩니다.

angular.module('myApp', [])
.directive('pluginNameOrWhatever', function() {
  return function(scope, element, attrs) {        
    setTimeout(function doWork(){
      //jquery code and plugins
    }, 0);        
  };
});

이 경우 $ timeout을 사용하지 않는 이유를 궁금해하는 사람에게는 완전히 불필요한 다른 다이제스트주기가 발생합니다.


1

ng-repeat가 끝난 후에 MathJax를 사용하여 수식을 렌더링해야했지만 위의 답변 중 어느 것도 내 문제를 해결하지 못했기 때문에 다음과 같이 만들었습니다. 그것은의 멋진 솔루션을하지 ,하지만 나를 위해 일한 ...

<div ng-repeat="formula in controller.formulas">
    <div>{{formula.string}}</div>
    {{$last ? controller.render_formulas() : ""}}
</div>

0

나는 여기에서 잘 연습 된 답변을 찾았 지만 여전히 지연을 추가해야했습니다.

다음 지시문을 작성하십시오.

angular.module('MyApp').directive('emitLastRepeaterElement', function() {
return function(scope) {
    if (scope.$last){
        scope.$emit('LastRepeaterElement');
    }
}; });

다음과 같이 속성으로 repeater에 추가하십시오.

<div ng-repeat="item in items" emit-last-repeater-element></div>

Radu에 따르면,

$scope.eventoSelecionado.internamento_evolucoes.forEach(ie => {mycode});

나를 위해 작동하지만 여전히 setTimeout을 추가해야합니다

$scope.eventoSelecionado.internamento_evolucoes.forEach(ie => {
setTimeout(function() { 
    mycode
}, 100); });

-4

클래스 이름을 변경하여 다르게 렌더링되도록하려면 아래 코드에서 트릭을 수행하십시오.

<div>
<div ng-show="loginsuccess" ng-repeat="i in itemList">
    <div id="{{i.status}}" class="{{i.status}}">
        <div class="listitems">{{i.item}}</div>
        <div class="listitems">{{i.qty}}</div>
        <div class="listitems">{{i.date}}</div>
        <div class="listbutton">
            <button ng-click="UpdateStatus(i.$id)" class="btn"><span>Done</span></button>
            <button ng-click="changeClass()" class="btn"><span>Remove</span></button>
        </div>
    <hr>
</div>

이 코드는 쇼핑 목록에 쇼핑 항목을 Strick trough 글꼴로 렌더링 해야하는 비슷한 요구 사항이있을 때 효과적이었습니다.

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