ng2-pdf-viewer: 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 );
  }
}

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 8
  • Comments: 32 (1 by maintainers)

Most upvoted comments

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.

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>

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.

I see that the demo page doesn’t have the bug when changing zoom: https://vadimdez.github.io/ng2-pdf-viewer/ even with my own .pdf loaded into the demo. My package.json is in the standalone demo, as you can see I am using angular 5.2 and angular-cli 1.7.1

You can open it in the app if you specific the target to be equal to _self and _system if you want to open in the device browser checkout this https://github.com/apache/cordova-plugin-inappbrowser

Unfortunately, I did not find any solutions yet. However, I replaced it with webview instead. So when users want to read a PDF take them to a webview instead, it work perfectly.

Actually I can’t reproduce the problem in the example while zooming.

But using the change in pdf_viewer.js solves my problem.

I’ll keep investigating

If I wrap the zoom with the isLoaded flag, it still show the error. Any ideas?

Hey so I had the same issue. I noticed that if you added a bounds check for index it fixes the issue. The problem is actually with another package that ng2-pdf-viewer depends on.

Line 555: pdf_viewer.js

function backtrackBeforeAllVisibleElements(index, views, top) {
  if (index < 2 || views.length <= index) {
    return index;
  }
  console.log('index: ', index, 'view length: ', views.length);
  
  var elt = views[index].div;

So I am pretty sure that ng2-pdf-viewer has to run this check before calling

backtrackBeforeAllVisibleElements

I get this also when changing the [zoom] parameter…