与ng-repeat相同的元素指令,需要首先运行ng-repeat并使用其值

时间:2013-06-29 22:39:41

标签: html5 angularjs video.js angularjs-ng-repeat

我正在尝试将video.js库连接到我的应用中。在应用程序的一部分,用户可以上传可能包含视频的文件,因此在输出时,我使用ng-repeat循环播放视频,并输出HTML5视频标记。我现在想要将一个指令附加到视频标记,以便video.js可以与它一起使用。

我的视频输出定义为

<video ng-src="{{video.url}}" ng-repeat="video in post.attachments.video" type="{{video.mimetype}}" controls preload="metadata" id="video_{{video.id}}" video>

对于我的video指令,我基本上只想运行videojs函数来设置它,所以我想调用

videojs(attrs.id, {
    controls: true,
    preload: "metadata",
    techOrder: ["flash"]
  }, function() {});

这是被调用的,但我遇到的问题是ng-repeat在调用此指令时尚未完成所有操作,因此attrs.id仍然是video_{{video.id}}而不是我想要的video_23

在我的视频指令运行之前,我怎么能等到ng-repeat完成它的事情所以我知道我可以使用ID属性?

我目前正在使用Angular 1.1.4。

现在,我的指示已经

app.directive("video", function($parse) {
  "use strict";
  return {
    restrict: "A",
    link: function(scope, elm, attrs) {

      videojs(attrs.id, {
        controls: true,
        preload: "metadata",
        techOrder: ["flash"]
      }, function() {});
    }
  };
});

3 个答案:

答案 0 :(得分:1)

问题是在尝试访问插值时尚未执行字符串插值。您可以使用attrs.$observe(...)来完成此操作。以下是AngularJS文档的link(或在下面阅读)。

...
link: function(scope, element, attrs) {
  attrs.$observe('id', function() {
    videojs(attrs.id, {
      controls: true,
      preload: "metadata",
      techOrder: ["flash"]
    }, function() {});
  });
}
...

我还创建了一个显示此行为的plunker

修改:更新了正确答案。

编辑2 :来自Angular文档:

  

使用$observe观察包含的属性的值更改   插值(例如src="{{bar}}")。这不仅非常有效   但它也是轻松获得实际价值的唯一方法,因为   在链接阶段,尚未评估插值   所以此时的值设置为undefined。

答案 1 :(得分:0)

您可以为指令指定priority。来自文档AngularJS: Directives

  

priority - 当在单个DOM元素上定义了多个指令时,有时需要指定应用指令的顺序。优先级用于在调用编译函数之前对指令进行排序。优先级定义为数字。首先编译具有更高数字优先级的指令。具有相同优先级的指令的顺序是未定义的。默认优先级为0。

编辑: 实际上,这看起来非常类似于这个问题:How to get evaluated attributes inside a custom directive

答案 2 :(得分:0)

最后有一个解决方案。这不是最好的(由于角度缺乏回调),但它正在发挥作用。我的最终指示是

app.directive("video", function($timeout) {
  "use strict";
  return {
    restrict: "A",
    compile: function(cElm, cAttrs) {
      return function postLink(scope, elm, attrs) {
        // We have to wait until it's actually rendered. Stupid angular with no callback!
        $timeout(function() {
          videojs(scope.$eval(attrs.video), {
            controls: true,
            preload: "metadata",
            techOrder: ["flash"]
          }, function() {});
        })
      }
    }
  };
});

我还必须将html的定义更改为

<video ng-src="{{video.url}}" ng-repeat="video in post.attachments.video" type="{{video.mimetype}}" controls preload="metadata" id="video_{{video.id}}" video="'video_' + video.id">

请注意在video属性中添加了表达式,因为id属性中使用的表达式无法在eval中使用。

我还必须使用烦人的$timeout hack,因为尝试初始化视频。对于元素ID的j.js没有工作,因为角度没有完成呈现元素,所以当video.js尝试要在DOM中找到具有该ID的元素,它与任何内容都不匹配。使用$timeout修复此问题虽然我并不过分热衷于此。

如果有人对此有更好的解决方案,那么我全都耳朵:)