Out of bounds index in pdf_viewer: “TypeError: Cannot read property ‘div’ of undefined” – when closing PDF too quickly – or zooming

Seems to be a race-condition type of bug, if I close the pdf viewer too quickly. (or change [zoom])

I get this with ng2-pdf-viewer v5.1.1 (angular 5.2) in Chrome if I close (set *ngIf=false the parent’s div) too quickly before the PDF is totally loaded… I have a “close” button that kills the pdfviewer parent div. To guard it, to only be able to close when the PDF is loaded, I am catching the (after-load-complete) and (page-rendered), not allowing to set the pdfviewer parent div’s ngIf to false unless those have completed, but still getting the crash/exception.

TypeError: Cannot read property 'div' of undefined
    at backtrackBeforeAllVisibleElements (VM474151 pdf_viewer.js:558)
    at getVisibleElements (VM474151 pdf_viewer.js:605)
    at PDFViewer._getVisiblePages (VM474151 pdf_viewer.js:5400)
    at PDFViewer.forceRendering (VM474151 pdf_viewer.js:5080)
    at PDFRenderingQueue.renderHighestPriority (VM474151 pdf_viewer.js:4191)
    at continueRendering (VM474151 pdf_viewer.js:4256)
    at ZoneDelegate.invoke (VM472116 zone.js:388)

offending line of code is here in pdf_viewer.js:558:

function backtrackBeforeAllVisibleElements(index, views, top) {
  if (index < 2) {
    return index;
  }
  var elt = views[index].div;   <----- HERE pdf_viewer.js:558

where index == 3 for my 3-page pdf (out of bounds!).

The html template:

<div *ngIf='showing' (click)="close()">
<div (click)="$event.stopPropagation()">
<pdf-viewer
	[src]='content_url'
        [zoom]='pdfzoom'
	[original-size]="false"
	[render-text]="true"
	[autoresize]="true"
	[show-all]="true"
	[fit-to-page]="false"
	(after-load-complete)="onPdfLoad($event)"
	(error)="onPdfError($event)"
	(on-progress)="onPdfProgress($event)"
	(page-rendered)="onPdfRendered($event)"
></pdf-viewer>
</div>
</div>

the component.ts

close() {
   if (this.can_close) this.showing = false;
}
onPdfLoad(e) {
  this.can_close = true;
}
zoomIn() {
  if (this.can_close) {
    this.pdfzoom = Math.min( this.pdfzoom_max, this.pdfzoom+0.1 );
  }
}
zoomOut() {
  if (this.can_close) {
    this.pdfzoom = Math.max( this.pdfzoom_min, this.pdfzoom-0.1 );
  }
}

5 thoughts on “Out of bounds index in pdf_viewer: “TypeError: Cannot read property ‘div’ of undefined” – when closing PDF too quickly – or zooming

  1. The question I have, is then:

    • How is anyone using ng2-pdf-viewer without running into all kinds of these pdf.js crashes?

    Follow on question:

    • Am I using ng2-pdf-viewer wrong somehow? Feels like my simple [zoom] increment/decrementer can’t possibly be abusing the system…. It’s so simple… like it’s exposing an internal bug of ng2-pdf-viewer.
  2. Very Simple Demo which reproduces, using vadimdez’s pdf:

    See here for a minimal, self contained, Angular 5.2.0 app: https://github.com/subatomicglue/ng2pdfViewerTest

    The code added is thus:

    Added to app.component.html:

    <div (click)="pdfshow = !pdfshow">close</div>
    <div (click)="pdfzoom=1 < (pdfzoom+0.1) ? 1 : (pdfzoom+0.1)">zoomin</div>
    <div (click)="pdfzoom=(pdfzoom-0.1) < 0.1 ? 0.1 : (pdfzoom-0.1)">zoomout</div>
    <div *ngIf='pdfshow'>
    	viewer:
    	<pdf-viewer *ngIf="pdfshow" (click)="$event.stopPropagation()" style='background-color:black;display: block;'
    		[src]="'https://vadimdez.github.io/ng2-pdf-viewer/assets/pdf-test.pdf'"
    		[original-size]="false"
    		[render-text]="true"
    		[autoresize]="true"
    		[show-all]="true"
    		[zoom]="pdfzoom"
    		[fit-to-page]="false"
    	></pdf-viewer>
    </div>
    

    Added to app.component.ts:

      pdfshow:boolean = true;
      pdfzoom:number = 0.8;
    

    If I hit close too quick, or hit zoomin/zoomout too quick, I’ll get the same crash as above.

  3. I also encountered this bug @subatomicglue . I attempted a similar solution to yours. (guarding zoom/close with a loading flag)

    In my case I solved the problem by only setting the loaded flag once all pages have rendered. (See below example)

    It would be great if the lib could maybe emit an additional (after-render-complete) event or something.

    I know this still remains a less-than-optimal workaround but perhaps it helps you 🙂

    Container component class:

    export class PdfViewerComponent {
    
      // ... 
    
      loaded = false;
      showPdf = true; 
      pageCount: number;
      pagesRendered = 0;
    
      pdfLoaded = event => {
        this.pageCount = event.pdfInfo.numPages;
      };
    
      pageRendered = () => {
        this.pagesRendered += 1;
        if (this.pagesRendered === this.pageCount) {
          this.renderComplete();
        }
      };
    
      renderComplete = () => {
        this.loaded = true;
      }
    
      close = () => {
         if (this.loaded) {
            this.showPdf = false;
         }
      }
    
      // ...
    
    }

    Container component template:

    <div *ngIf="showPdf">
      <pdf-viewer [src]="pdfSrcConfig"
                  [autoresize]="true"
                  [original-size]="false"
                  (page-rendered)="pageRendered($event)"
                  (after-load-complete)="pdfLoaded($event)"
      ></pdf-viewer>
    </div>