19

I have a scope like $scope.doc_details in my angularjs controller, and I want to use it to display a pdf file by using a tag, like this:

<object data="{{doc_details.file_url}}" type="application/pdf"></object>

but it doesn't get loaded in the browser, in my chrome console, all I see is:

Failed to load resource: the server responded with a status of 404 (Not Found) 
http://localhost/%7B%7Bdoc_details.file_url%7D%7D

and when I just display it using <span>{{doc_details.file_url}}</span> it show the value.

AT_
  • 223
  • 1
  • 2
  • 12

4 Answers4

34

As of AngularJS 1.1.4, you can use the ng-attr- prefix for the data attribute:

<object ng-attr-data="{{doc_details.file_url}}" type="application/pdf"></object>

See the ngAttr for binding to arbitrary attributes section on AngularJS: Interpolation and data-binding.

Sean Leather
  • 1,182
  • 1
  • 9
  • 25
  • 3
    This will not work with IE. IE will not let you change the data attribute after it has been loaded. You'll likely get a message box saying that access is denied. You should load it via a directive instead to delay the binding. – user2339814 Mar 23 '16 at 20:02
  • is that still the case now? I can't seem to easily google "object html element angularjs" i get a bunch of results about passing software objects and not html element objects. I'm getting strange issues with my code. Any updated answer to this or a link to docs will help thanks :) – Kyle Calica-St Apr 13 '16 at 02:04
  • This is still the case with IE 11. – Todd Palmer Dec 13 '16 at 23:04
  • Noting that I've not had any success with this method on AngularJS 1.7. – snazzybouche Nov 07 '19 at 21:10
25

The problem here is that the browser is seeing

<object data="{{doc_details.file_url}}" type="application/pdf"></object>

in the DOM before Angular compiles it, and obviously {{doc_details.file_url}} isn't a valid URL.

Directives can be your friend here.

Say we want to write:

<pdf src='doc_details.file_url'></pdf>

We can create a directive:

app.directive('pdf', function() {
    return {
        restrict: 'E',
        link: function(scope, element, attrs) {
            var url = scope.$eval(attrs.src);
            element.replaceWith('<object type="application/pdf" data="' + url + '"></object>');
        }
    };
});

This will defer the creation of the object element until we actually have the URL available to us from the scope (assuming it's already there - otherwise you'd want to $watch the src attribute on the scope until it became available).

Here this is in a fiddle.

Kees de Kooter
  • 7,078
  • 5
  • 38
  • 45
satchmorun
  • 12,487
  • 2
  • 41
  • 27
  • Ran into this problem while using angular2. Any thoughts on how to use data-binding with tag? – ellier7 Aug 17 '18 at 16:01
  • @satchmorun Finally this was the solution that worked for me. Indeed delaying the binding was the trick. Thanks! – Souvik Ray Jan 20 '21 at 14:58
1

Thank you satchmorun, but if smb want change link without reloading page or modal you can use:

<pdf2 src="pdfUrl" height="heightForPDF"></pdf2>

And this directive:

app.directive('pdf2', ['$compile', function ($compile) {
    return {
        restrict: 'E',
        scope: {
            src: "=",
            height: "="
        },
        link: function (scope, element, attr) {
            function update(url) {
                    element.html('<object data="' + url + '" type="application/pdf" width="100%" style="height: ' + scope.height + 'px">' +
                        'Для просмотра pdf:<br /> Для Internet Explorer установите <a target="_blank" href="http://get.adobe.com/reader/">Acrobat Reader</a><br />' +
                        'Для Chrome: <a target="_blank" href="https://support.google.com/chrome/answer/6213030?hl=ru">Проверьте настройки</a>' +
                        '</object>');
                    $compile(element.contents())(scope);
            }
            scope.$watch('src', update);
        }
    };
}]);

Thank you Jerry from this answer and example of recompile a dynamically loaded directive.

p.s. "pdfUrl" and "heightForPDF" are variable in scope

0

The browser tries to process the thing before AngularJS replaced the angulary expression with something the browser can work with, causing an error.

Adding an ng-cloak fixes the issue.

Ivan Rubinson
  • 3,001
  • 4
  • 19
  • 48