내가 구현하려고하는 것은 기본적으로 “반복 완료 렌더링시”처리기입니다. 언제 완료되었는지 감지 할 수는 있지만 함수를 트리거하는 방법을 알 수는 없습니다.
바이올린을 확인하십시오 : http://jsfiddle.net/paulocoelho/BsMqq/3/
JS
var module = angular.module('testApp', [])
.directive('onFinishRender', function () {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
element.ready(function () {
console.log("calling:"+attr.onFinishRender);
// CALL TEST HERE!
});
}
}
}
});
function myC($scope) {
$scope.ta = [1, 2, 3, 4, 5, 6];
function test() {
console.log("test executed");
}
}
HTML
<div ng-app="testApp" ng-controller="myC">
<p ng-repeat="t in ta" on-finish-render="test()">{{t}}</p>
</div>
답변 : 마무리 작업에서 바이올린 작업 : http://jsfiddle.net/paulocoelho/BsMqq/4/
답변
var module = angular.module('testApp', [])
.directive('onFinishRender', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
$timeout(function () {
scope.$emit(attr.onFinishRender);
});
}
}
}
});
내가 사용 .ready()
하지 않고에 래핑했습니다 $timeout
. $timeout
ng-repeated 요소가 렌더링을 완전히 마쳤을 때 실행되는지 확인하십시오 ( $timeout
현재 다이제스트주기의 끝에서 will이 실행 되기 때문에 – 와 $apply
달리 내부적으로 호출됩니다setTimeout
). 따라서이 ng-repeat
작업이 끝나면 $emit
외부 범위 (형제 및 부모 범위)로 이벤트를 내보내는 데 사용 됩니다.
그런 다음 컨트롤러에서 다음과 $on
같이 잡을 수 있습니다 .
$scope.$on('ngRepeatFinished', function(ngRepeatFinishedEvent) {
//you also get the actual event object
//do stuff, execute functions -- whatever...
});
html을 사용하면 다음과 같이 보입니다.
<div ng-repeat="item in items" on-finish-render="ngRepeatFinished">
<div>{{item.name}}}<div>
</div>
답변
DOM이 생성 된 후 브라우저가 렌더링되기 전에 콜백 (예 : test ())을 실행 하려면 $ evalAsync를 사용하십시오 . 이 떨림을 방지 할 수 있습니다 – 심판 .
if (scope.$last) {
scope.$evalAsync(attr.onFinishRender);
}
깡깡이 .
렌더링 후 콜백을 실제로 호출하려면 $ timeout을 사용하십시오.
if (scope.$last) {
$timeout(function() {
scope.$eval(attr.onFinishRender);
});
}
이벤트 대신 $ eval을 선호합니다. 이벤트의 경우 이벤트 이름을 알고 해당 이벤트의 컨트롤러에 코드를 추가해야합니다. $ eval을 사용하면 컨트롤러와 지시문 사이의 연결이 줄어 듭니다.
답변
지금까지 제공된 답변은 처음 ng-repeat
렌더링 될 때만 작동 하지만 동적 인 경우 ng-repeat
항목을 추가 / 삭제 / 필터링 할 것이고 매번 알림을 받아야 함을 의미합니다.ng-repeat
렌더링되면 해당 솔루션이 작동하지 않습니다.
따라서 처음으로뿐만 아니라 다시 렌더링을 받는다는 통지를 받아야 할ng-repeat
때, 나는 그것을 할 수있는 방법을 찾았습니다. 하기. 이 옵션을 사용 $filter
하여에 ng-repeat
당신이 다른를 사용하기 전에$filter
:
.filter('ngRepeatFinish', function($timeout){
return function(data){
var me = this;
var flagProperty = '__finishedRendering__';
if(!data[flagProperty]){
Object.defineProperty(
data,
flagProperty,
{enumerable:false, configurable:true, writable: false, value:{}});
$timeout(function(){
delete data[flagProperty];
me.$emit('ngRepeatFinished');
},0,false);
}
return data;
};
})
이 때마다 $emit
전화 이벤트ngRepeatFinished
ng-repeat
렌더링 입니다.
사용 방법:
<li ng-repeat="item in (items|ngRepeatFinish) | filter:{name:namedFiltered}" >
ngRepeatFinish
필터의 요구는 직접 적용 할 Array
또는은 Object
으로 정의하여$scope
, 당신은 후에 다른 필터를 적용 할 수 있습니다.
사용하지 않는 방법 :
<li ng-repeat="item in (items | filter:{name:namedFiltered}) | ngRepeatFinish" >
다른 필터를 먼저 적용한 다음 필터를 적용하지 마십시오 ngRepeatFinish
.
언제 사용해야합니까?
목록 렌더링이 완료된 후 특정 CSS 스타일을 DOM에 적용하려는 경우 다음에 의해 다시 렌더링 된 DOM 요소의 새로운 차원을 고려해야합니다. ng-repeat
. (BTW : 이러한 종류의 작업은 지시문 내에서 수행해야합니다)
ngRepeatFinished
이벤트 를 처리하는 함수에서 수행하지 말아야 할 것 :
-
$scope.$apply
해당 함수에서을 수행하지 마십시오. 그렇지 않으면 Angular가 감지 할 수없는 무한 루프에 Angular를 배치하게됩니다. -
$scope
속성 을 변경하는 데 사용하지 마십시오. 변경 사항은 다음$digest
루프 까지보기에 반영 되지 않으며 수행 할 수 없으므로 사용$scope.$apply
하지 않습니다.
“그러나 필터는 그런 식으로 사용되지 않습니다 !!”
아니, 그들은, 그것은 당신이 그것을 사용하지 않는 것을 좋아하지 않는 경우, 해킹입니다. 같은 것을 성취하는 더 좋은 방법을 알고 있다면 알려주십시오.
요약
이것은 해킹 이며 잘못된 방식으로 사용하는 것은 위험하므로
ng-repeat
렌더링이 완료된 후에 스타일을 적용하는 데만 사용하면 아무런 문제가 없습니다.
답변
동일한 컨트롤러에서 다른 ng-repeats에 대해 다른 함수를 호출 해야하는 경우 다음과 같이 시도 할 수 있습니다.
지시어 :
var module = angular.module('testApp', [])
.directive('onFinishRender', function ($timeout) {
return {
restrict: 'A',
link: function (scope, element, attr) {
if (scope.$last === true) {
$timeout(function () {
scope.$emit(attr.broadcasteventname ? attr.broadcasteventname : 'ngRepeatFinished');
});
}
}
}
});
컨트롤러에서 $ on으로 이벤트를 잡으십시오.
$scope.$on('ngRepeatBroadcast1', function(ngRepeatFinishedEvent) {
// Do something
});
$scope.$on('ngRepeatBroadcast2', function(ngRepeatFinishedEvent) {
// Do something
});
여러 번 반복되는 템플릿에서
<div ng-repeat="item in collection1" on-finish-render broadcasteventname="ngRepeatBroadcast1">
<div>{{item.name}}}<div>
</div>
<div ng-repeat="item in collection2" on-finish-render broadcasteventname="ngRepeatBroadcast2">
<div>{{item.name}}}<div>
</div>
답변
다른 솔루션은 초기 페이지로드에서 제대로 작동하지만 컨트롤러에서 $ timeout을 호출하는 것이 모델이 변경 될 때 함수가 호출되도록하는 유일한 방법입니다. $ timeout을 사용 하는 작동하는 바이올린 은 다음과 같습니다 . 귀하의 예를 들면 다음과 같습니다.
.controller('myC', function ($scope, $timeout) {
$scope.$watch("ta", function (newValue, oldValue) {
$timeout(function () {
test();
});
});
ngRepeat는 행 내용이 새로운 경우에만 지시문을 평가하므로 목록에서 항목을 제거하면 onFinishRender가 실행되지 않습니다. 예를 들어, 이러한 바이올린 방출 에 필터 값을 입력하십시오 .
답변
이중 달러 범위 소품을 사용하지 않고 내용 만 반복되는 지시문을 작성하는 경우 매우 간단한 해결책이 있습니다 (초기 렌더링에만 관심이 있다고 가정). 링크 기능에서 :
const dereg = scope.$watch('$$childTail.$last', last => {
if (last) {
dereg();
// do yr stuff -- you may still need a $timeout here
}
});
이것은 렌더링 된 목록의 멤버의 너비 또는 높이를 기반으로 DOM 조작을 수행 해야하는 지시문이있는 경우에 유용하지만 (이 질문을 할 가능성이 가장 큰 이유라고 생각합니다) 제안 된 다른 솔루션으로.
답변
필터링 된 ngRepeat 의이 문제에 대한 해결책은 다음과 같습니다. 돌연변이 이벤트와 관련이 있었지만 더 이상 사용되지 않습니다 (즉시 교체하지 않음).
그런 다음 또 다른 쉬운 것을 생각했습니다.
app.directive('filtered',function($timeout) {
return {
restrict: 'A',link: function (scope,element,attr) {
var elm = element[0]
,nodePrototype = Node.prototype
,timeout
,slice = Array.prototype.slice
;
elm.insertBefore = alt.bind(null,nodePrototype.insertBefore);
elm.removeChild = alt.bind(null,nodePrototype.removeChild);
function alt(fn){
fn.apply(elm,slice.call(arguments,1));
timeout&&$timeout.cancel(timeout);
timeout = $timeout(altDone);
}
function altDone(){
timeout = null;
console.log('Filtered! ...fire an event or something');
}
}
};
});
이것은 한 번의 $ timeout으로 부모 요소의 Node.prototype 메소드에 연결되어 연속적인 수정을 감시합니다.
대부분 올바르게 작동하지만 altDone이 두 번 호출되는 경우가 있습니다.
다시 …이 지시어를 ngRepeat 의 부모 에 추가하십시오 .