在指令内加载后访问子元素图像

时间:2015-03-13 13:19:54

标签: javascript angularjs angularjs-directive

我正在尝试创建一个指令来对子图像执行缩放。使用ng-repeat嵌入图像,URL来自父控制器中的REST API调用。这是指令的嵌入:

这是指令的模板:

<div>
    <img image-directive-item ng-src="{{image.url}}" ng-style="{'width': {{image.width}}, 'height': {{image.height}}}" ng-if="image.done" />
</div>

要缩放每张图片,我需要获取信息:周围其他图像的宽度/高度。目前,我试图在绑定到图像的子指令中将此信息传递给父级。这是我正在测试的代码:

angular.module("myApp")
.directive("imageDirective", function() {
    return {
        scope: { images: '=images'},
        link: function(scope){

            for(var i = 0; i < scope.images.length; i++) {
                console.log(scope.images[i].width, scope.images[i].height);
            }

        },
        templateUrl: _contextPath + 'static/html/imageDirective.html'
    };
})
.directive("imageDirectiveItem", function() {
    return {
        link: function(scope, element) {
            element.bind("load", function(e) {
                scope.image.width = this.naturalWidth;
                scope.image.height = this.naturalHeight;
            });
        }
    };
});

图像正在页面上加载,加载回调可以读取尺寸,但是控制台中的输出(来自父指令)对于所有图像都是“未定义的未定义”,并且有关无法设置宽度/高度为空值。

我想以这种格式进行,因为我需要按照它们在DOM中出现的顺序处理图像。然而,我正在努力使这两个连接不依赖于什么感觉像黑客。有什么想法吗?


New Dev提供的解决方案适用于我。修改了元素如何传递给父指令,以便它从加载回调传递对象,其中包含我需要的信息。今天学到了一些关于Angular的新知识!

angular.module("myApp")
.directive("imageDirective", function() {
    return {
        scope: { images: '=images'},
        controller: function($scope){

            var toBeLoaded = $scope.images.length;

            this.childLoaded = function(childElement) {
                console.log(childElement.naturalWidth, childElement.naturalHeight);

                if(--toBeLoaded == 0) {
                    allChildrenLoaded();
                }
            };

            function allChildrenLoaded() {
                console.log("All children loaded.");
            }

        },
        templateUrl: _contextPath + 'static/html/imageGrid.html'
    };
})
.directive("imageDirectiveItem", function() {
    return {
        require: "^imageDirective",
        link: function(scope, element, attrs, imageDirectiveCtrl) {
            element.bind("load", function() {
                var e = this;
                scope.$apply(function() {
                    imageDirectiveCtrl.childLoaded(e);
                });
            });
        }
    };
});

控制台输出:

414 415
507 338
366 468
432 395
500 354
507 338
414 414
478 358
507 338
All children loaded.

2 个答案:

答案 0 :(得分:2)

您打印undefined undefined的原因是因为在您进行for循环时没有加载任何图像。

如果您需要&#34;处理&#34; (正如你所说)父结果中的结果,然后在范围暴露的对象上设置值可能不是最好的方法。例如,你怎么知道它已经完成加载?如果没有昂贵的深$watch,你怎么知道某些事情发生了变化?

我认为更好的方法是公开子指令可以调用的API。这是通过在父母的控制器上公开一个功能并在孩子身上使用require: "^imageDirective"来完成的。

.directive("imageDirective", function(){
  return {
    // .. whatever you currently have
    controller: function($scope){
      var toBeLoaded = 0;
      this.registerChild = function(childElem){
         toBeLoaded++;
      };

      this.childLoaded = function(childElem){
         toBeLoaded--;
         // do whatever processing you need
      };
    }
  }
})
.directive("imageDirectiveItem", function(){
  return {
    require: "^imageDirective",
    link: function(scope, element, attrs, imageDirectiveCtrl){
       imageDirectiveCtrl.registerChild(element);

       element.bind("load", function(){
          scope.$apply(function(){
             imageDirectiveCtrl.childLoaded(element);
          })
       })
    }
  }
}

答案 1 :(得分:0)

如果您使用的是最新浏览器(IE&gt; = 11),可以尝试MutationObserver

imageDirective的链接功能中尝试此操作。

var observer = new MutationObserver(function(mutations) {
        mutations.forEach(function(mutation) {
            var target = mutation.addedNodes && mutation.addNodes[0],
                targetScope; 
            if (target) {
                target = angular.element(target);
                targetScope = target.scope();
                console.log(targetScope.width, targetScope.height) 
            }
        });    
});

var config = {childList: true};

observer.observe(element[0], config);