Last active
September 9, 2025 18:27
-
-
Save joelkesler/6760e79b5000ca99657b8023698b6051 to your computer and use it in GitHub Desktop.
iFrame on Unload Directive (for Angular v20 and up) - Track when an iframe url changes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { Directive, ElementRef, OnInit, OnDestroy, inject, output } from '@angular/core'; | |
| /** | |
| * This directive is designed to monitor iframe navigation or reloads by listening to the `unload` event | |
| * on the iframe's `contentWindow`. It emits an `iframeUnload` output event, allowing parent components | |
| * to react to changes in the iframe's content. | |
| * | |
| * Note: Due to cross-origin restrictions, the directive may not work if the iframe loads content from | |
| * a different domain. In such cases, a warning is logged to the console. | |
| * | |
| * Usage: | |
| * ```html | |
| * <iframe appIframeUnload (iframeUnload)="getIframeLocation()"></iframe> | |
| * ``` | |
| * | |
| * ```ts | |
| * @Component({ | |
| * selector: 'app-example', | |
| * //... | |
| * }) | |
| * export class ExampleComponent | |
| * //... | |
| * | |
| * iframe = viewChild.required<ElementRef>('iframe'); | |
| * | |
| * getIframeLocation() { | |
| * const iframeElement = this.iframe().nativeElement; | |
| * if (iframeElement && iframeElement.contentWindow) { | |
| * const newLocation = iframeElement.contentWindow.location; | |
| * console.log('Iframe location:', newLocation.href); | |
| * } | |
| * } | |
| * } | |
| * ``` | |
| * | |
| * @selector iframe[appIframeUnload] | |
| * @standalone | |
| */ | |
| @Directive({ | |
| selector: 'iframe[appIframeUnload]', | |
| standalone: true, | |
| }) | |
| export class IframeUnloadDirective implements OnInit, OnDestroy { | |
| private el = inject(ElementRef<HTMLIFrameElement>); | |
| iframeUnload = output<void>(); | |
| ngOnInit() { | |
| const iframe = this.el.nativeElement; | |
| iframe.onload = () => { | |
| try { | |
| iframe.contentWindow.onunload = () => { | |
| // Use setTimeout to ensure the iframe has time to update its location | |
| setTimeout(() => { | |
| this.iframeUnload.emit(); | |
| }, 0); | |
| }; | |
| } catch (e) { | |
| console.warn( | |
| 'IframeUnloadDirective: Could not attach unload listener to iframe (likely cross-origin):', | |
| e, | |
| ); | |
| } | |
| }; | |
| } | |
| ngOnDestroy() { | |
| const iframe = this.el.nativeElement; | |
| if (iframe.contentWindow) { | |
| iframe.contentWindow.onunload = null; | |
| } | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment