AngularJS - 操纵DOM后NG重复完成 [英] AngularJS - Manipulating the DOM after ng-repeat is finished

查看:145
本文介绍了AngularJS - 操纵DOM后NG重复完成的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我通过数据循环之后经历有关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.


  1. 确认 NG-重复已完成,与火的物品的事件计数。看 $最后属性 - 我们可以通过连接一个控制器,一个唯一的目的这样做。一旦它的发现(有truthy值),我们将触发一个事件来通知一下吧:

  1. 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:


    1. 装点 NG-SRC 指令,所以它发送的图像加载时的事件:

    1. 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屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆