angularjs $compile 对 iframe 上的 onload 事件进行错误处理

Posted

技术标签:

【中文标题】angularjs $compile 对 iframe 上的 onload 事件进行错误处理【英文标题】:angularjs $compile bugs the onload event on an iframe 【发布时间】:2015-11-18 08:30:17 【问题描述】:

我正在尝试创建一个打印提供程序,它接收模板和范围并将其编译为 html,而不是在 body 标记中注入带有此 html 内容的 iframe,并在 iframe 上的 onload 事件上调用 print 以打印此内容内容。 代码如下所示:

myApp.provider('$print', function() 
    return 
        $get: function($document, $interpolate, $compile, $timeout) 
            var $print = ;

            function printFrame(content) 
              var frameContent = '<!doctype html>' +
                  '<html>' +
                    '<body onload="window.print()">' +
                      content +
                    '</body>' +
                  '</html>';

              // inject iframe into DOM
              var iframe = document.createElement("IFRAME");
              iframe.id = 'print-frame';
              iframe.style.display = 'none';

              var body = $document.find('body').eq(0);
              body.append(iframe);
              iframe = document.getElementById('print-frame');

              // fill iframe with print content
              var iframeContent = (iframe.contentWindow) ? iframe.contentWindow : (iframe.contentDocument.document) ? iframe.contentDocument.document : iframe.contentDocument;
              iframeContent.document.open();
              iframeContent.document.write(frameContent);
              iframeContent.document.close();
            ;

            $print.iframe1 = function(printOptions) 
                var printScope = printOptions.scope.$new();
                var htmlToPrint = $interpolate(printOptions.template)(printScope);
                printFrame(htmlToPrint);
            

            $print.iframe2 = function(printOptions) 
                var printScope = printOptions.scope.$new();
                $timeout(function() 
                    var htmlToPrint = $compile(printOptions.template)(printScope);
                    printScope.$digest();
                    printFrame(htmlToPrint.html());
                );
            

            return $print;
        
    
);

我遇到的问题是,例如,当我使用 $interpolate 时,提供程序工作正常,iframe onload 事件等到图像和所有内容都加载后才调用打印,但是当我使用 @987654326 @,由于某种原因,iframe 的 onload 事件在图像加载之前触发。

我为这个例子创建了一个 JSFiddle,如果你禁用缓存,你可以看到在插值时,打印仅在加载大图像后调用,但在编译时,打印消息立即打开。

希望有人可以帮助我,在此先感谢丹尼尔!

http://jsfiddle.net/HB7LU/16737/

【问题讨论】:

【参考方案1】:

htmlToPrint 确实有两个元素 h1 和另一个是 img 标签,但问题是当您从 iframe2 函数执行 htmlToPrint.html() 时,它只返回 SuperHero,它没有'不返回 html 的其他部分。

为了解决这个问题,你可以使用一些 div 来包装你的模板,这样在对元素执行 .html() 时将返回正确的元素。

模板

template: '<div>'+
            '<h1>printTitle</h1>'+
            '<img style="width: 1000px" src="http://velocityagency.com/wp-content/uploads/2013/08/go.jpg"'>+'
          '<div>',

此外,您需要在$timeout 函数中设置一些以毫秒为单位的少量超时,例如10

$timeout(function() 
    printFrame(htmlToPrint.html());
,10);

Working Fiddle

更新

如果我禁用了浏览器缓存,上述解决方案不起作用,我认为我们在在页面上呈现图像之前发送一个页面进行打印。

$print.iframe2 = function(printOptions, scope) 
    var printScope = printOptions.scope.$new();
    var htmlToPrint = $compile(printOptions.template)(printScope);

    angular.element(htmlToPrint.find('img').on('load', function() 
        $timeout(function() 

            console.log("Img loaded")
            printFrame(htmlToPrint.html());
        );
    ))


Updated Fiddle

【讨论】:

你说得对,我更新了我的 JSFiddle 但这并不能解决我遇到的问题,$compile 打印仍然会在图像加载之前打开 brwoser 打印模式,所以打印里面没有图片 @PacuraruDaniel 看看我的编辑..会解决你的问题..谢谢:) @PankajParkar 我认为超时 0 应该没问题(以便 $digest 完成)。 @PankajParkar 嘿伙计,我试过小提琴,但它对我做同样的事情,当我打开编译打印时,第一次没有图像,你可以看到如果你禁用缓存和刷新页面后打开 @DeblatonJean-Philippe nope..我已经试过了。我很惊讶这不起作用..这就是为什么我包含超时值..【参考方案2】:

我发现了这个问题,问题是当我编译 html 时,图像开始下载并被浏览器缓存,当我将它们注入 iframe 时,iframe 上的 onload 事件认为它们已经下载,无需等待。

【讨论】:

以上是关于angularjs $compile 对 iframe 上的 onload 事件进行错误处理的主要内容,如果未能解决你的问题,请参考以下文章

Angularjs+Typescript 指令实现 $compile

angularJS DOM element() $compile()

AngularJS:使用 $compile 将 html 附加到网页

angularjs指令中的compile详解

AngularJS:在包含带有 templateurl 的指令的 html 上使用 $compile

Angularjs:错误:[$compile:ctreq] 控制器“carousel”,指令“ngTransclude”需要,找不到