AngularJS - 操纵DOM后NG重复完成 [英] AngularJS - Manipulating the DOM after ng-repeat is finished
问题描述
我通过数据循环之后经历有关DOM操纵的一些问题。
I'm experiencing some problems regarding manipulation of the DOM after looping through the data.
我们有一个依赖于数据和正常工作jQuery的滑块插件,但是当使用 NG-重复
,我们必须包装它的初始化与 $超时
为它工作—而现在甚至没有工作。
We have a jQuery slider plugin that is tied to data and works normally, but when using ng-repeat
, we have to wrap its initialization with $timeout
for it to work — and now that isn't even working.
我想使用 $超时
是靠不住的,这对于一个坏的修复。在jQuery中,我可以使用 $(文件)。就绪()
—这是坚实的,但使用 angular.element(文件)。就绪()
似乎并没有擦出火花。
I think using $timeout
is unreliable, which makes for a bad fix. In jQuery I could use $(document).ready()
— which was solid, but using angular.element(document).ready()
doesn't seem to work either.
滑块指令被调用,但由于图像没有被加载到DOM&MDASH不能获得在滑块的图像的高度;致使滑动件具有0计算高度
The slider directive is invoked but cannot obtain the height of the images in the slider because the images have not been loaded into the DOM — resulting in the slider having a calculated height of 0.
我发现目前它非常令人沮丧 - 必须有操纵数据后DOM的方式(在 NG-重复
)后已经走过循环。
I'm finding it very frustrating at the moment - there must be a way to manipulate the DOM after data (in an ng-repeat
for example) has cycled through.
滑块的初始化如下进行:
The Initialization of the slider is performed as follows:
var sliderLoad = function () {
$timeout(function () {
var setHeight = elem.find('.slide:eq(0)').outerHeight(true);
elem.css({
height: setHeight
});
}, 1000);
// Show the slider nav buttons
elem.parent().find('.direction-nav').show();
};
…这里是一个 再现演示
… and here is a reproduction demo.
推荐答案
我们希望确保所有图像加载,所以让我们写一个指令:
We would want to make sure that all images are loaded, so let's write a directive for that:
app.directive('loadDispatcher', function() {
return {
restrict: 'A',
link: function(scope, element, attrs) {
element.bind('load', function() {
scope.$emit('$imageLoaded');
});
}
};
})
…并将其连接到 NG-SRC
'D元素:
<img class="thumb-recipe" ng-src="{{ object.tile_url }}" load-dispatcher/>
现在我们可以比较赶上我们的模型的事件的数量,并作为所需的
Now we can compare the number of events caught with our model, and act as needed:
var loadCount = 0;
scope.$on('$imageLoaded', function () {
if (loadCount++ === scope.videos.objects.length - 1) {
_initSlider(); // act!
}
});
这是一个令人不安的一点,因为它不是秉承法律德米特&MDASH的;任何指令,它会看 $ imageLoaded
事件必须知道关于模型( scope.videos.objects.length
)。
This is a little disturbing, as it's not adhering to the Law of Demeter — any directive that will watch the $imageLoaded
event will have to know about the model (scope.videos.objects.length
).
我们可以prevent通过找出多少图像没有明确解决模型加载这种耦合。让我们假设该事件将在办理NG-重复
。
We can prevent this coupling by finding out how many images were loaded without explicitly addressing the model. Let's assume that the events will be handled in an ng-repeat
.
-
确认
NG-重复
已完成,与火的物品的事件计数。看$最后
属性 - 我们可以通过连接一个控制器,一个唯一的目的这样做。一旦它的发现(有truthy值),我们将触发一个事件来通知一下吧:
Make sure
ng-repeat
has finished, and fire an event with the items count. We can do that by attaching a controller with a sole purpose - to watch the$last
property. Once it's found (with a truthy value), we will fire an event to notify about it:
.controller('LoopWatchCtrl', function($scope) {
$scope.$watch('$last', function(newVal, oldVal) {
newVal && $scope.$emit('$repeatFinished', $scope.$index);
});
})
<div ng-repeat="object in videos.objects" ng-controller="LoopWatchCtrl">
现在,赶上事件并相应地激活滑块初始化:
Now, catch the events and activate the slider initialization accordingly:
var loadCount = 0,
lastIndex = 0;
scope.$on('$repeatFinished', function(event, data) {
lastIndex = data;
});
scope.$on('$imageLoaded', function() {
if (lastIndex && loadCount++ === lastIndex) {
_initSlider(element); // this is defined where-ever
}
});
有,现在我们的指令不必知道模型。但是,这是一个有点麻烦,现在我们要绑一条指令的和的控制器。
There, now our directive does not have to know about the model. But, it's a bit cumbersome, now we have to tie a directive and a controller.
让我们来提取这整个shabang成一个单一的指令:
Let's extract this whole shabang into a single directive:
app.directive('imageLoadWatcher', function($rootScope) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
if (typeof $rootScope.loadCounter === 'undefined') {
$rootScope.loadCounter = 0;
}
element.find('img').bind('load', function() {
scope.$emit('$imageLoaded', $rootScope.loadCounter++);
});
},
controller: function($scope) {
$scope.$parent.$on('$imageLoaded', function(event, data) {
if ($scope.$last && $scope.$index === $rootScope.loadCounter - 1) {
$scope.$emit('$allImagesLoaded');
delete $rootScope.loadCounter;
}
});
}
};
});
&hellip;这将被应用到 NG-重复
ED元素:
<div ng-repeat="object in videos.objects" class="slide" image-load-watcher>
现在我们可以简单地看 $ allImagesLoaded
例如在滑块:
Now we can simply watch $allImagesLoaded
e.g. in the slider:
scope.$on('$allImagesLoaded', function() {
_initSlider(element);
});
我们可以再次分解并应用这种方法的应用范围使用的事件指派的任何的 NG-重复
完成或 NG-SRC
负载,这并不总是必要的( 1 ),但可以是非常有用的。让我们看看如何:
We can break it down again and apply this approach app-wide to use event dispatching for any ng-repeat
finish or ng-src
load, which is not always necessary (1), but can be quite useful. Let's see how:
-
装点
NG-SRC
指令,所以它发送的图像加载时的事件:
Decorate the
ng-src
directive, so it sends an event when an image is loaded:
app.config(function($provide) {
$provide.decorator('ngSrcDirective', function($delegate) {
var directive = $delegate[0],
link = directive.link;
directive.compile = function() {
return function(scope, element, attrs) {
link.apply(this, arguments);
element.bind('load', function() {
scope.$emit('$imageLoaded');
});
};
};
return $delegate;
});
// ...
});
装饰 NG-重复
通知,当它完成:
app.config(function($provide) {
// ...
$provide.decorator('ngRepeatDirective', function($delegate) {
var directive = $delegate[0],
link = directive.link;
directive.compile = function() {
return function(scope, element, attrs) {
link.apply(this, arguments);
scope.$watch('$$childTail.$last', function(newVal, oldVal) {
newVal && scope.$emit('$repeatFinished');
});
};
};
return $delegate;
});
});
现在可以捕捉事件的任何地方,例如在你的滑块指令:
Now can catch the events anywhere, e.g. in your slider directive:
var repeatFinished = false;
var loadCount = 0;
scope.$on('$repeatFinished', function() {
repeatFinished = true;
});
scope.$on('$imageLoaded', function () {
if (repeatFinished &&
loadCount++ === scope.videos.objects.length - 1) {
_initSlider(); // this is defined where-ever
}
});
这似乎击败宗旨,我们又回到了原点,但它可以是非常强大的。并且还与MDASH;看,妈妈,没有新的指令!
It seems to defeat the purpose, as we're back to square one, but it can be very powerful. And also — look, mommy, no new directives!
<div ng-repeat="object in videos.objects" class="slide">
<img class="thumb-recipe" ng-src="{{ object.tile_url }}"/>
</div>
<一个href=\"http://plnkr.co/edit/tdGUfrVHetqTZHi7Dpd9?p=$p$pview\">
TL;DR,只要给我演示塔! ! !&NBSP;&NBSP;&NBSP;&NBSP;&NBSP;&
NBSP; 骨节病>
1 即可。装修必须仔细考虑,因为其结果将派出跨应用程序加载的每个图像上的一个事件。
1. Decoration has to be considered carefully, as the result will be sending an event on each image loaded across the application.
&公牛; 重写链接
功能将不会在1.3.x版可能起。
• Overriding the link
function will not be possible in version 1.3.x onwards.
这篇关于AngularJS - 操纵DOM后NG重复完成的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!