Reputation: 3947
I am trying to embed a PDF document in an HTML view, with a Knockout ViewModel providing the URL for the document. I believe that the correct HTML element for this is <object>
, so I have the following view:
<div class="documentviewerpdf">
<object data-docType="pdf" data-bind="attr: { 'data': EmbedPDFLink }" type="application/pdf" width="100%" />
</div>
and the following as a view model:
function AppViewModel() {
this.EmbedPDFLink = "http://acroeng.adobe.com/Test_Files/browser_tests/embedded/simple5.pdf";
}
ko.applyBindings(new AppViewModel());
This displays the PDF in Chrome, Chrome Canary (both using native Chrome PDF plugin), and Firefox 27 (Adobe Reader XI plugin), however all three browsers display a warning in a bar across the top of the screen. Chrome's is yellow and states that it Could not load Chrome PDF Viewer
, while Firefox's is grey with an information icon and states that this PDF document might not be displayed correctly
. The same code loads the plugin empty on IE9.
If I replace the data-bind
attribute with a direct data
attribute containing the hard coded URL for the PDF document, Chrome and Firefox display correctly, while IE9 displays nothing at all, not even the empty plugin.
I have tried setting the data
attribute using a <param>
element within the <object>
as well, and that did not work at all in any of these browsers.
I have also tried using an <embed>
tag, which gives similar results though works in IE9, however this does not seem like it is semantically correct. However, the embed element documentation states that any attributes are passed to the plugin - given that the elements are so similar, is it likely that the data-bind
attribute is being passed to the PDF plugins, and causing this problem?
It appears that the only difference in mark-up between the hardcoded and data-bind
versions is the presence of a data-bind
attribute on the latter, so I think that is causing the problem with the plugins, as the data
URL attribute is being set correctly.
Is there a way to set the data
attribute on the object using Knockout, without leaving a data-bind
attribute there as well? Is there another way that anyone knows to avoid this issue?
Upvotes: 2
Views: 2083
Reputation: 14995
Use bindings to keep all of your attributes hidden until the source path has been evaluated. The plugin sees your other attributes and thinks you have a bad element.
data-bind="attr: { 'each-attribute-here': true }"
Chrome recognizes your PDF too quickly, before the value is evaluated. Tie all of the properties that the plugin is looking for into your binding.
You could also use a custom binding here to add the attributes and pass in the value of the location of the PDF. This custom binding handler should not directly inject HTML into the DOM.
Upvotes: 1
Reputation: 3702
I'm not 100% sure, but I think this is what's happening.
Your html markup has an <object data-docType='pdf' />
- so that is there immediately upon DOM load. However, the data
attribute of it is using a KO binding. So immediately upon DOM load when the <object>
html element is loaded, the KO bindings aren't applied just yet and you get the error.
I tested it out, and I constructed the <object>
html markup in Javascript and then added it to the DOM and the error went away. Hope it helps, see fiddle
function AppViewModel() {
this.EmbedPDFLink = "http://acroeng.adobe.com/Test_Files/browser_tests/embedded/simple5.pdf";
this.addPdf = function () {
var html = "<object data-docType=\"pdf\" data=\"" + this.EmbedPDFLink + "\" type=\"application/pdf\" width=\"100%\" />";
$('.documentviewerpdf').append(html);
};
}
ko.applyBindings(new AppViewModel());
and the HTML
<button data-bind="click: addPdf">Load PDF</button>
<div class="documentviewerpdf"></div>
Here's an updated fiddle that will automatically load the PDF when you get to the page (more in line with what you want your end result to be, I think). I tested it in IE, FIrefox, and Chrome (latest versions) and received no errors.
Upvotes: 2