Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Stop angular reloading iframes when changing components?

Tags:

angular

I have an angular application which I built based on ngxadmin.

https://github.com/akveo/ngx-admin

It's on Angular 4.4.6.

The app changes between different dashboards. Each of these dashboards has an iframe with some embedded charts.

The problem is that every time I change the dashboard, the iframe reloads.

The reload takes 1-2 seconds and isn't super fast when compared to the main angular app (which is entirely cached).

The problem is that every time an iframe is injected into the HTML it causes it to reload. The rendered content isn't preserved.

I've read a lot of places and this is a fundamental design of iframes. If you remove / insert them back into the DOM they are reloaded.

I've also tried to make them as FAST as possible by using HTTP caching and a CDN (Fastly). That improves the situation but I'm still faced with these slow load times.

Is there a way I can prevent the iframe from reloading every time?

Is there a way I can have angular not REMOVE the HTML content but instead just display:none it so that it's still actually part of the DOM?

Another idea I thought of was rendering the iframe hidden, then copying the body innerHTML and moving it into my angular app. Then just using that content. I'm not super concerned about security since I control both apps but I imagine the CSS would be broken at that point.

One idea is I could just write the pre-rendered HTML into the iframe instead of relying on fetching it from 'src' each time.

like image 727
Kevin Burton Avatar asked Jan 17 '18 17:01

Kevin Burton


3 Answers

I don't know if my problem is exactly the same as yours, but I've had an issue when using the sanitizer.bypassSecurityResourceUrl as the src for the iframe:

<iframe [src]="sanitizer.bypassSecurityTrustStyle(url)"></iframe>

'url' here is of type string. This resets the iframe in every changeDetection. To overcome this a custom directive could be used:

<iframe [cachedSrc]="url"></iframe>

This is the code for the directive:

@Directive({
  selector: 'iframe'
})
export class CachedSrcDirective {

    @Input() 
    public get cachedSrc(): string {
        return this.elRef.nativeElement.src;
    }
    public set cachedSrc(src: string) {
        if (this.elRef.nativeElement.src !== src) {
            this.renderer.setAttribute(this.elRef.nativeElement, 'src', src);
        }
    }

    constructor(
        private elRef: ElementRef,
        private renderer : Renderer2
        ) { }
}

As long as the iframe is in the DOM tree and the src is not changed, this will work I guess. No need for bypassing URL's using the DomSanitizer either :)

like image 72
Ernstjan Freriks Avatar answered Oct 15 '22 20:10

Ernstjan Freriks


sorry for the late response, but I've encountered the same problem when embedding youtube videos on mi app. I wasn't able to fullscreen the embedded videos due to some on resize handler being called which triggered change detection and reloaded the iframe.

Anyway, I managed to solve this issue using the ChangeDetectorRef from @angular/core which seems to be available since angular 2.

what I did was:

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

@Component({
  selector: 'app-your-component',
  templateUrl: './your-component.component.html', // here goes your iframe
  styleUrls: ['./your-component.component.scss']
})
export class YourComponent implements AfterViewInit {

  constructor( private ref: ChangeDetectorRef ) { }

  ngAfterViewInit() {
    this.ref.detach()
  }
}

I know this is a workaround, but is not like you are going to detach your whole application, you are only preserving your already loaded iframe. Additionally you'll remove that little piece anyway when the rest of your template updates.

Hope this helps you or others with the same issue.

like image 7
Eric Van Der Dijs Avatar answered Oct 15 '22 18:10

Eric Van Der Dijs


I had a similar issue, using Angular 12. However, I couldn't use a directive, as the HTML was loaded from an external source. Furthermore, detaching the change detection stopped the iframes from loading altogether. Using OnPush Change detection strategy worked perfectly.

like image 1
Andrew_W Avatar answered Oct 15 '22 19:10

Andrew_W