Search code examples
htmlangulartypescriptangular2-components

Angular2 embedded object type binding not works


I have written an angular2 component to display embedded documents, but when I try to bind the mimetype of document it is not working.

html:

<div class="embed-responsive" *ngIf="mimeType!==null">
        <object [attr.data]="url" 
                [attr.type]="mimeType"
                class="embed-responsive-item">
                <embed [attr.src]="url"
                       [attr.type]="mimeType"/>
        </object>
</div>

working html without type binding:

<div class="embed-responsive" *ngIf="mimeType!==null">
        <object [attr.data]="url" 
                type="application/pdf" 
                class="embed-responsive-item">
                <embed [attr.src]="url"
                       type="application/pdf"/>
        </object>
</div>

typescript code:

import { Component, Input, HostListener } from "@angular/core";
import { AttachmentFile } from "../../model/dockModel";
import { DomSanitizer, SafeUrl } from '@angular/platform-browser';

    @Component({
        selector: "document-viewer-inline",
        templateUrl: "docview/components/document-viewer-inline-component/document-viewer-inline-component.html"
    })
    export class DocumentViewerInlineComponent {

        private attachment: AttachmentFile;

        public url: SafeUrl = null;
        public mimeType: string = null;

        constructor(private sanitizer: DomSanitizer) {
        }

        @Input()
        public set attachmentFile(f: AttachmentFile) {
            this.attachment = f;
            if (this.attachment !== null && this.attachment !== undefined) {
                this.url = this.sanitizer.bypassSecurityTrustResourceUrl("/attachment/contentById/" + this.attachment.componentId);            
                this.mimeType = f.mimeType;
            }
        }

        public ngOnInit() {
            this.calculateInlineHeight();        
        }

    }

My question is: how can I bind the type attribute of embedded and object?


Solution

  • I haven't found where it's explicitly stated but I'm pretty sure <object> doesn't support dynamic changes to the type attribute and requires it to be set statically.

    See also Changing data content on an Object Tag in HTML

    Below workaround doesn't work - see comments:

    A hack could be

        <object *ngIf="mimeType!==null" [attr.data]="url" 
                [attr.type]="mimeType"
    
     constructor(private cdRef:ChangeDetectorRef) {}
    
     private _mimeType:string=null;
     public get mimeType():string { return this._mimeType; }
     public set mimeType(value:string) {
       this._mimeType = null;
       this.cdRef.detectChanges();
       this._mimeType = value;
       this.cdRef.detectChanges();
     }
    

    To make this more convenient to use you could wrap this with a custom <my-object> component.

    UPDATED hack:

    public showObject: boolean = true;
    public url: String = null;
    // public url: SafeUrl = null;
    
    constructor(@Inject(DomSanitizer) private sanitizer: DomSanitizer,
                @Inject(ChangeDetectorRef) private cdRef: ChangeDetectorRef) {
    }
    
    @Input()
    public set attachmentFile(f: FetAttachmentFile) {
        this.attachment = f;
        if (this.attachment !== null && this.attachment !== undefined) {
            this.url = null;
            this.mimeType = null;
            this.showObject = false;
            this.cdRef.detectChanges();
            this.url = "/attachment/contentById/" + this.attachment.componentId;
            // this.url = this.sanitizer.bypassSecurityTrustResourceUrl("/attachment/contentById/" + this.attachment.componentId);
            this.mimeType = f.mimeType;
            this.showObject = true;
            this.cdRef.detectChanges();
        }
    }
    
    public innerHtml() {
        return this.sanitizer.bypassSecurityTrustHtml( 
            "<object data='" + this.url + "' type='" + this.mimeType + "' class='embed-responsive-item'>" +
            "<embed src='" + this.url + "' type='" + this.mimeType + "' />" +
            "</object>");
    }
    

    html code:

    <div class="embed-responsive" 
         [style.height]="inlineHeight"
         *ngIf="showObject"
         [innerHTML]="innerHtml()">
    </div>