1

When a components in bootstrap's modal dialog, it keeps rerendering couple of times per second. (I see it in browsers developer tools).

The component looks like this:

@Component({
  selector: 'app-takeover',
  encapsulation: ViewEncapsulation.None,
  changeDetection: ChangeDetectionStrategy.OnPush,
  template: `

<iframe #iframe 
        [src]="sanitizer.bypassSecurityTrustResourceUrl(takeover.IframeUrl)"
        sandbox="allow-same-origin" 
        (load)="iframe_load($event)">
</iframe>

   `,
})
export class TakeoverComponent {

  constructor(
     public sanitizer: DomSanitizer
  ) { }

  takeover: Takeover;

  @ViewChild('iframe') iframeRef: ElementRef<HTMLIFrameElement>;

  iframe_load(event) { }
}

and I show it like this:

let modalRef = this.modalService.open(TakeoverComponent);
let component = modalRef.componentInstance as TakeoverComponent;
component.takeover = takeover;

When I remove (load)="iframe_load($event)" from the template, it renders just once as expected.

Why it keeps rerendering the DOM and how do I prevent it from doing so?

"@angular/core": "~7.2.0", "@ng-bootstrap/ng-bootstrap": "^4.2.1", "zone.js": "~0.8.26"

Liero
  • 25,216
  • 29
  • 151
  • 297

1 Answers1

1

That's probably because of this:

<iframe 
  #iframe 
  [src]="sanitizer.bypassSecurityTrustResourceUrl(takeover.IframeUrl)" 
  sandbox="allow-same-origin" 
  (load)="iframe_load($event)">
</iframe>

You've binded the src property on the iframe to a method. What is happening is that the method is getting called on every change detection. Hence the re-rendering.

Consider using a pipe for this to prevent the rerendering:

<iframe 
  #iframe 
  [src]="takeover.IframeUrl | safe: 'url'" 
  sandbox="allow-same-origin" 
  (load)="iframe_load($event)">
</iframe>

Get the safe pipe implementation from my answer here.

PS: I haven't tested this out but should work just fine.

Assigning a method call to Property Bindings, Attribute Bindings and String Interpolations can lead to unnecessary re-renders / performance hits. I've shortly touched upon this aspect in a Medium Article. You might want to read it too.

There's also a StackOverflow Answer that talks about this.

Community
  • 1
  • 1
SiddAjmera
  • 38,129
  • 5
  • 72
  • 110
  • safe pipe seems to help, but 1. why it was rerendering only when there was the (load) event handler. 2. the method returns the same url, so why it should be a problem? I guess it does not return string, but some reference type – Liero Jul 30 '19 at 14:09
  • The answer only says, that the method will be evaluated on every change detection, but it doesn't explain the rerendering. It should rerender, only when return value of the method changes. It also does not explain why it happens only when there is (load) even handler. BTW, notice that my component is using Push detection strategy, so the change detection should occur (although it is for some reason) – Liero Jul 30 '19 at 14:20
  • By saying that it happens only when there is `(load)` event handler, do you mean that re-rendering doesn't happen if you remove `(load)` event handler from the `iframe`. If so, do you mind replicating this on a Sample StackBlitz so that this could be investigated? – SiddAjmera Jul 30 '19 at 14:26