角度:<embed /> PDF-避免由于DOM修改而重新加载多个PDF

时间:2018-08-21 09:45:20

标签: angular pdf dom

上下文

  • 库:Angular(5 +),Angular材质
  • 单个网页。
    • 用户提交ID后,我的应用向服务器请求数据
    • 这些数据包含指向pdf文件的URL。
    • PDF将显示在Angular组件中,该组件包含HTML模板,该模板包含HTML embed 标签。
      • 使用 ngFor
      • 显示组件
    • 用户可以按类别(与每个PDF关联的一些元数据)过滤PDF
      • 目前,该实现正在重新排序 ngFor 使用的组件列表,以便可见组件首先出现在列表中。另一个移动后,将隐藏的CSS可见性应用于这些其他组件以隐藏

问题

  • 应用过滤器后,我经常看到PDF文件再次(从磁盘缓存)下载到嵌入HTML元素中
    • 但是只有在对基础列表进行重新排序时才会发生
      • 我想是因为列表的种类导致DOM修改
  • 是否可以将PDF文件仅下载一次到DOM -embedd元素中?
  • 我在这篇文章的底部放了一些相关代码,可以帮助您了解我所做的事情

预先感谢您的帮助! :)

import {Component, OnInit} from '@angular/core';

import {MatCheckbox} from '@angular/material';


import {MissionDocumentStoreService} from '../mission-document-store.service';
import {MissionDocumentChangeDetectorService} from '../mission-document-change-detector.service';
import {MissionPdf} from '../mission-pdf';


// Observable
import {Observable} from 'rxjs/Observable';
import {Subject} from 'rxjs/Subject';

// Observable operators
import 'rxjs/add/observable/fromEvent';
import 'rxjs/add/operator/switchMap';
import 'rxjs/add/operator/takeUntil';

@Component({
  selector: 'app-pdf-grid',
  templateUrl: './pdf-grid.component.html',
  styleUrls: ['./pdf-grid.component.css']
})
export class PdfGridComponent implements OnInit {

  private ngUnsubscribe: Subject<void> = new Subject<void>();
  pdfCategoriesToHide = new Set<string>([]);


  displayedPdfs: MissionPdf[] = [];


  constructor(public docStoreService: MissionDocumentStoreService,
    private dataChangeDetectorService: MissionDocumentChangeDetectorService) {}

  ngOnInit() {
    this.dataChangeDetectorService.dataChange$
      .takeUntil(this.ngUnsubscribe)
      .subscribe(value => {
        this.pdfCategoriesToHide.clear();
        this.displayedPdfs = this.reorderPdfByCategory();
      },
      error => {
        console.error(error);
        //        this.handleError();
      }
      );

  }

  changeCategoryCheckbox(e) {
    const checkbox = e.source as MatCheckbox;
    const category = checkbox.id;
    // XXX: Retrieve category from id instead of from  _elementRef.nativeElement.innerText or textContent
    // because the second method may produce a text different than the original
    // which will cause problems when using this value for comparison.

    if (checkbox.checked) {
      this.pdfCategoriesToHide.delete(category);
    } else {
      this.pdfCategoriesToHide.add(category);
    }
    this.displayedPdfs.length = 0;
    this.displayedPdfs = this.reorderPdfByCategory();
  }

  displayPdf(pdf: MissionPdf): string {
    const value = !this.pdfCategoriesToHide.has(pdf.pdfType) ? 'visible' : 'hidden';
    return value;
  }

  reorderPdfByCategory(): MissionPdf[] {
    const allPdfs = this.docStoreService.data;
    if (!this.pdfCategoriesToHide) {
      return allPdfs;
    }

    const pdfsToShow = [];
    const pdfsToHide = [];

    let pdf, hide;
    for (let i = 0; i < allPdfs.length; i++) {
      pdf = allPdfs[i];
      hide = this.pdfCategoriesToHide.has(pdf.pdfType);
      if (!hide) {
        pdfsToShow.push(pdf);
      } else {
        pdfsToHide.push(pdf);
      }
    }
    return pdfsToShow.concat(pdfsToHide);
  }

  trackByIndex(index: number, pdf: MissionPdf): number {
    return pdf.index;
  }

}
<!-- THE HTML file of my PdfGridComponent -->
<!-- It shows multiple <app-pdf-element> -->

<div class="counters-panel">
  <b>Pdfs</b> <span *ngIf="docStoreService.count !== null">&nbsp;(Téléchargés
		= {{docStoreService.count}} / Total = {{docStoreService.totalCount}})</span>
</div>

<!-- The filter on PDF categories.-->
<!-- For each category, there is one checkbox.-->
<!-- When a checkbox is unchecked the correspond PDFs should not be displayed.-->
<div class="pdf-category-filter-box">
  <mat-checkbox *ngFor="let category of docStoreService.pdfCategories" (change)="changeCategoryCheckbox($event)" class="pdf-category" [checked]="true" [labelPosition]="'before'" [id]="category">{{category}}</mat-checkbox>
</div>

<!-- The grid displaying the PDFs-->
<div class="pdf-grid">
  <app-pdf-element *ngFor="let doc of displayedPdfs; trackBy: trackByIndex" [doc]="doc" [style.visibility]="displayPdf(doc)">
  </app-pdf-element>
</div>

<!--
Below is the content of my <app-pdf-element> that should display a PDF file.

==HTML part==
<div *ngIf="innerHtmlForPdf" class="pdf-container" [innerHTML]="innerHtmlForPdf"></div>

==Relevant JS part==
Build HTML code that contains the <embed> tag to display the PDF.
Then insert it in div.innerHTML so that it can be displayed on Chrome but also Edge.

  @Input()
  set doc(doc: MissionDocument) {
    if (!this.pdfDoc) {
      this.pdfDoc = doc;
      this.innerHtmlForPdf = this.sanitizer.bypassSecurityTrustHtml(
        '<embed  src=\'' + this.getPdfUrlWithoutToolbar() + '\' type=\'application/pdf\' '
        + 'style=\'border-style: solid; border-color: black;    border-width: thick; cursor: pointer; '
        + ' background: url("./assets/img/loading-spinner.gif") no-repeat center;'
        + 'height: 100%;     width: 100%; position: absolute; z-index: -1;\'>'
        + '<div style=\'border-style: solid; border-color: black;    border-width: thick; cursor: pointer;'
        + 'height: 100%;     width: 100%; position: absolute; z-index: 1;\'></div>'

        + '<div style=\'border-style: solid; border-color: black; border-width: thick; cursor: pointer;'
        + 'background-color: black;'
        + 'height: 100%; width: 3%; position: absolute; right:-5px; z-index: 1;\'></div>'
      );
    }
  }
-->

0 个答案:

没有答案