4

I have an AngularJS directive:

myApp.directive('movie', function(){
return {
    restrict: 'E',
    replace: true,
    scope: { product:'=', codebase: '@' },
    template: '<object style="width:550px;height:320px;" name="movie" id="movie" codebase="{{codebase}}"' +
              ' classid="clsid:D27CDB6E-AE6D-11cf-96B8-444553540000" tabindex="-1">' +
              '<param value="{{product.flashURL}}" name="movie">' +
              '<param value="true" name="play">' +
              '<param value="true" name="menu">' +
              '<param value="transparent" name="wmode">' +
              '<param value="noscale" name="scale">' +
              '<embed wmode="transparent" style="width:550px;height:320px;" src="{{product.flashURL}}" scale="noscale"' +
              ' pluginspage="http://www.macromedia.com/go/getflashplayer" play="true" name="movieEmbed" menu="true" id="movieEmbed">' +
              '</object>'
};});

It is used like this:

<movie product="productInScope" codebase="http://flashcodebase..." />

I made this directive to fix the problem I was having by simply including this HTML in a view, which is this: the instant the object tag is rendered, the Flash attempts to load a movie at the URL "{{product.flashURL}}". That obviously fails, and by the time Angular gets around to interpolating the expression, it's too late.

Unfortunately, restructuring it as a directive didn't help the problem. Interestingly, the {{codebase}} expression seems to always work; maybe it evaluates first, causing the Flash to load and attempt to fetch the URL?

How would you rewrite this directive (or use some simpler approach) so that the object tag is not created until the flashURL is available?


I ran into a similar issue trying to embed a PDF via directive. The problem is that when the template is placed into the DOM the bindings have not yet been interpolated, as @mfelix supposes. However it is trickier because object invokes code outside the browser so it isn't guaranteed to play well with invalid or dynamic attributes (depends on the plugin I suppose).

I wound up having to write a link function, which $observes the variable, just as in the ng-src/ng-href solution. In the case of ng-src or ng-href, the $observe callback on the variable simply sets the corresponding attribute and everything works because HTML5 (or as we used to call it, DHTML) is cool like that. For example, you might have an <a> tag without a corresponding href. The browser handles this just fine. And when you set an href on it after the first Angular digest, the browser can deal with it. But for the <object> tag, it doesn't work so well, because even if the plugin is misconfigured (say, missing src attribute), the browser has no way of knowing that and it will still invoke the corresponding plugin, which will treat missing information in a highly idiosyncratic way. In my case, Firefox handled it gracefully and Chrome barfed.

So the next approach I tried was to use the $observing callback to inject a child element containing the fully specified object tag (concatenating the variable into the template string using the + operator).

Simplified example directive definition:

scope: ...
link: function(scope, element, attrs) {
        attrs.$observe('src', function(value) {
          if (value) {
            element.html(
              '<object width="100%" type="application/pdf" data="'+value+'">');
          } else {
            element.html("<div></div>"); // We have to put something into the DOM
          }
        });
      },
 etc: ...

When src finally has a value, and when its value changes, the callback you register via $observe will be invoked.

My third solution, which I like best, was to process the PDFs into GIFs and display them as images, completing forgoing accursed plugins (and no, PDF.js wasn't cutting it). So maybe you can turn your Flash movies into animated .gifs. That would be awesome.

4

1 回答 1

11

我在尝试通过指令嵌入 PDF 时遇到了类似的问题。问题是当模板被放入 DOM 时,绑定还没有被插入,正如@mfelix 所假设的那样。然而它更棘手,因为object调用浏览器之外的代码,所以不能保证它可以很好地使用无效或动态属性(取决于我想的插件)。

我最终不得不编写一个link函数,其中$observes的变量,就像在ng-src/ng-href解决方案中一样。在ng-srcor的情况下ng-href,变量的$observe回调只是设置了相应的属性,一切正常,因为 HTML5(或者我们以前称之为 DHTML)就像那样很酷。例如,您可能有一个<a>没有相应href. 浏览器处理得很好。当你href在第一个 Angular 摘要之后设置它时,浏览器可以处理它。但对于<object>标签,它并不能很好地工作,因为即使插件配置错误(例如,缺少 src 属性),浏览器也无法知道,它仍然会调用相应的插件,该插件将高度处理丢失的信息异想天开的方式。就我而言,Firefox 优雅地处理了它,而 Chrome 则被拒绝了。

所以我尝试的下一个方法是使用$observing回调来注入一个包含完全指定object标记的子元素(使用 + 运算符将变量连接到模板字符串中)。

简化示例指令定义:

scope: ...
link: function(scope, element, attrs) {
        attrs.$observe('src', function(value) {
          if (value) {
            element.html(
              '<object width="100%" type="application/pdf" data="'+value+'">');
          } else {
            element.html("<div></div>"); // We have to put something into the DOM
          }
        });
      },
 etc: ...

srcfinally 有一个值,并且当它的值改变时,你通过 $observe 注册的回调将被调用。

我最喜欢的第三个解决方案是将 PDF 处理为 GIF 并将它们显示为图像,完成上述被诅咒的插件(不,PDF.js 并没有削减它)。因此,也许您可​​以将您的 Flash 电影转换为动画 .gif。那将是真棒。

于 2013-03-08T01:19:09.967 回答