【问题标题】:Child Elements missing in Directive指令中缺少子元素
【发布时间】:2013-12-19 01:34:47
【问题描述】:

我定义了一个指令:

$(function () { angular.module(['myApp']).directive('rootSlider', function () { return { restrict: 'E', template: '<ul><li ng-repeat="item in items"><img ng-src="{{item.url}}" /></li></ul>', scope: { items: '=' }, replace: true, compile: function ($templateElement, $templateAttributes) { return function ($scope, $element, $attrs) { var $scope.items.length //expect 2, get 2 var numChildren $element.children().length //expect 2, get 0 }; } }; }); });

虽然$scope.items属性有2个元素,在最终渲染的DOM中有两个&lt;li&gt;元素,但在链接函数$element中还没有子元素。

在 Angular 生命周期的哪个阶段,我可以得到完全渲染的元素(我的意图是在这里使用 jQuery 滑块插件)。

标记是

<root-slider items="ModelPropertyWithTwoItems"></root-slider>

更新:

我能够通过 $watchCollection 和 $evalAsync 的组合使其正常工作。

$(function () {
    angular.module(['myApp']).directive('rootSlider', ['$timeout', function ($timeout) {
        return {
            restrict: 'E',
            template: '<ul class="bxslider"><li ng-repeat="item in items"><img ng-src="{{item.url}}" /></li></ul>',
            scope: {
                items: '='
            },
            compile: function ($templateElement, $templateAttributes) {
                return function ($scope, $element, $attrs) {
                    $scope.$watchCollection('items', function (newCollection, oldCollection) {
                        if ($scope.slider) {
                            $scope.$evalAsync(function () {
                                $scope.slider.reloadSlider();
                            });
                        }
                        else {

                            $scope.$evalAsync(function () {
                                $scope.slider = $element.find('.bxslider').bxSlider();
                            });
                        }

                    });

                };
            }
        };
    } ]);
});

Watch 集合在指令初始化时触发一次(因为它是一个集合,您无法比较 newValue 和 oldValue,因此我最终将滑块对象添加到为指令实例创建的 $scope 中。

我使用 $evalAsync 来推迟 jQuery 代码的执行,(到目前为止)证明可以避免在所有浏览器上闪烁(它似乎在 $timeout(function(){}, 0 之前运行)。

上面的解决方案可以通过只返回一个链接函数(而不是编译函数,结果证明是不必要的)来简化。

【问题讨论】:

    标签: jquery angularjs angularjs-directive


    【解决方案1】:

    在 Angular 中等待 DOM 完成渲染的常用方法是使用 $timeout。这是各种选项的explanationhere's another look at this

    所以这应该可以为您解决这个问题。在你的指令中包含$timeout

    angular.module(['myApp']).directive('rootSlider', function ($timeout) {
    

    然后包装你的

    $timeout(function() {
         var numChildren $element.children().length;
    },0);
    

    有一个request for a more official feature supporting this,这是 Angular 自己的 Misko Hevery 在他关闭问题之前的评论:

    所以这是一个非常复杂的问题。问题是,与 数据绑定更新周期没有明确的开始/结束,它是 继续。我确定这不是您正在寻找的答案,但是 angular 不像其他框架,所以它以不同的方式存在 规则。

    您认为这会如何运作?什么样的,什么时候应该 您会收到这些通知。

    到目前为止,似乎没有人对 3emad 接近尾声的这个问题做出回应:

    我只是对 $timeout 不利的一面感到好奇

    我认为这种方法令人鼓舞,因为目前还没有人发布缺点。

    【讨论】:

    • 这可行,但它会造成临时显示未格式化元素的情况。似乎会有一个更特定于框架的钩子。
    • $timeout 非常普遍地用于此 - 但我完全明白它看起来很笨拙。我很困惑你看到了一个你以前没有看到的闪光,因为这不应该延迟图像/模板的加载。还有其他东西在等待长度吗?这是一个超时延迟2秒的演示,但模板加载正常:jsfiddle.net/csnGL/2
    • 将此标记为答案。 $watch 解决方案没有专门解决该问题(尽管它很有帮助),并且指向您发布的功能请求的链接将我带到了 $evalAsync。谢谢!
    【解决方案2】:

    您可能想使用$watch 来赶上模型的变化。

    $scope.$watch('items', function(newValue) {
        // logic about items here...
    }, true); // pass true since it should be an array
    

    【讨论】:

    • 谢谢。我想出了类似的东西。我将很快更新这个问题,但我现在使用 $watchCollection,当它在初始化时触发 children().length 为 2(如预期的那样)。它在 IE(9) 上仍然闪烁,但看起来它适用于其他浏览器。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-04-24
    • 2013-11-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-01
    相关资源
    最近更新 更多