Resize event of an Angular2 application within an iframe has been triggered

My current project involves embedding an Angular2 application within a Liferay portlet using iframes. The Liferay tomcat server is hosted on a different domain than the Angular2 application, and I am facing challenges with dynamically resizing the iframe based on the content height of the Angular2 application. To tackle this issue, I am utilizing a helper file on the Liferay's tomcat server as suggested in the solution provided here.

This is a snippet of what I've implemented so far:

<html>
<!-- 
This page is on the same domain as the parent, so can
communicate with it to order the iframe window resizing
to fit the content 
-->
<body onload="parentIframeResize()">
<script>
    // Tell the parent iframe what height the iframe needs to be
    function parentIframeResize()
    {
        var height = getParam('height');
        // This works as our parent's parent is on our domain..
        parent.parent.resizeIframe(parseInt(height));
    }

    // Helper function to parse param from request string
    function getParam( name )
    {
        name = name.replace(/[\[]/,"\\\[").replace(/[\]]/,"\\\]");
        var regexS = "[\\?&]"+name+"=([^&#]*)";
        var regex = new RegExp( regexS );
        var results = regex.exec( window.location.href );
        if( results == null )
            return "";
        else
            return results[1];
    }
</script>
</body>
</html>

Within the JSP file in the Liferay portlet containing the iframe:

<iframe id="iframed-application"
        src="${baseUrl}:${externalTomcatPort}/${applicationName}/iframe?baseUrl=${baseUrl}:${port}">
</iframe>

<script>
    // Resize iframe to full height
    function resizeIframe(height) {
        document.getElementById('iframed-application').height = parseInt(height) + 10;
    }
</script>

In my Angular2 application's component HTML file:

<menu></menu>
<router-outlet></router-outlet>
<iframe id="helpframe" [src]='helperSource' height='0' width='0' frameborder='0'></iframe>

And the corresponding TypeScript code in the Angular2 application's component file:

import {Component} from "@angular/core";
import {OnInit} from "@angular/core";
import {ContextService} from "./common/service/context.service";
import {DomSanitizer} from "@angular/platform-browser";

@Component({
    selector: 'app-root',
    templateUrl: './app.component.html',
    styleUrls: ['./app.component.css']
})
export class AppComponent implements OnInit {
    helperSource;

    constructor(private sanitizer: DomSanitizer, private context: ContextService) {
    }

    ngOnInit(): void {
        let height = window.innerHeight;
        if (height < 800) height = 800;
        this.helperSource = this.sanitizer.bypassSecurityTrustResourceUrl(this.context.baseUrl + '/helper/helper.html' + '?height=' + height);
    }
}

Despite setting the initial iframe height during initialization, I'm now faced with the challenge of detecting resize events of the content within the angular app loaded in the iframe. Attempting to use '@HostListener('window:resize', ['$event'])' only captured window resize events rather than iframe resize events. Another approach involving accessing the contentWindow of the iframe also failed due to security restrictions related to cross-domain issues.

I'm seeking advice on whether there is a feasible way to listen for resize events within the iframed application or explore alternative solutions to address this issue.

Answer №1

Here is a piece of code that accomplishes this task

    import {CustomDirective, ElementRef, OnInit, Renderer} from "@angular/core";

@CustomDirective({
    selector: "[iframeAutoResize]"
})
export class IframeAutoResizeDirective implements OnInit {
    private elementRef: any;
    private renderService: Renderer;
    private previousHeight: number;
    private countSameHeight: number;

    constructor(_elementRef: ElementRef, _renderService: Renderer) {
        this.elementRef = _elementRef.nativeElement;
        this.renderService = _renderService;
    }

    ngOnInit() {
        const self = this;
        if (this.elementRef.tagName === "IFRAME") {
            this.renderService.listen(this.elementRef, "load", () => {
                self.previousHeight = 0;
                self.countSameHeight = 0;
                setTimeout(() => {
                    self.adjustHeight();
                }, 50);
            });
        }
    }

    adjustHeight() {
        const self = this;
        if (this.elementRef.contentWindow.document.body.scrollHeight !== this.previousHeight) {
            this.countSameHeight = 0;
            this.previousHeight = this.elementRef.contentWindow.document.body.scrollHeight;
            this.renderService.setElementStyle(
                self.elementRef,
                "height",
                this.elementRef.contentWindow.document.body.scrollHeight + "px"
            );
            setTimeout(() => {
                self.adjustHeight();
            }, 50);

        } else {
            this.countSameHeight++;
            if (this.countSameHeight < 2) {
                setTimeout(() => {
                    self.adjustHeight();
                }, 50);
            }
        }
    }
}

Instructions for Use:

<iframe [src]="urlForIframe" iframeAutoResize></iframe>

Answer №2

We have discovered that the best solution is to bind this to the onclick event on the body element. See the example code snippet below:

let body = document.getElementsByTagName('body')[0];

setTimeout(() => {
this.adjustHeight(body.offsetHeight);
}, 500);

body.addEventListener('click', () => {
this.adjustHeight(body.offsetHeight);
});

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for resolving NPM high severity vulnerabilities related to pollution issues

Every time I attempt to install npm packages, I encounter the same error message indicating "3 high severity vulnerabilities." When I execute the command npm audit fix, I consistently receive this: https://i.stack.imgur.com/3oJIB.png I have attempted to ...

The issue with AngularJS multiple $http requests failing to fetch accurate data

I'm having issues with my AngularJS controller and service modules. I want to refresh custController.allCustomers after adding a new customer so that the UI displays the new data. However, when I call custController.createCustomer, the new customer do ...

Variable passing value through google pie chart slices for offset

Using the Google Chart API and AngularJS, I am trying to set slice values through variables instead of hardcoding or using a foreach loop. How can I achieve this? In my code example below, the "selectedRow" variable is being passed as a string rather tha ...

Display/Conceal Content with Checkbox Utilizing jQuery

I have been attempting to create a section of an HTML form that will display or hide based on the status of a checkbox. Here is the key code snippet I am using: <script src="/js/jquery.js"></script> <script language="JavaScript"> fun ...

How to efficiently import an external ES module from a URL using TypeScript

I've recently started experimenting with Observable notebooks and I must say, it's been a great experience so far. Now, my next goal is to integrate a notebook into my web app. The following vanilla JavaScript code using JavaScript modules accomp ...

Select one href by clicking and apply addClass

I have a one-page HTML document with links in the header. I want to make it so that when I click on a link (<a>), only that specific link changes its class to (.links). I've tried various methods, but the current jQuery method I'm using ad ...

What is the best way to dynamically change the JSON-LD Script for the Schema?

Below is the script in question. Please read through it carefully. <script type="application/ld+json"> { "@context": "http://schema.org/", "@type": "Product", "name": "Bat, &q ...

Utilizing highcharts to visualize non-linear time data pulled from a CSV file

I am seeking guidance on implementing a simple graph based on data from a CSV file in web development. I lack experience in this area and have struggled to find a suitable example to follow. The CSV file contains data in the format of a unix timestamp, hu ...

Is there a way to iterate over an object with predetermined keys and then utilize those keys to access another object of the same type?

What I'm attempting to do next is calculate the total value of value in pounds. However, this is causing an error message stating: TS7053: Element implicitly has an 'any' type because expression of type 'string' can't be used ...

Generating fresh line with knockout effect

Currently in the process of developing a Single Page Application (SPA). Utilizing knockout and observable array to iterate through a json array. Encountering an issue where there are br tags present within the text, but when using data-bind="text: myVar" ...

Encountering an error "[$rootScope:inprog]" while using Angular select with ngModel

I'm still learning my way around Angular, but I have a basic understanding. Right now, I'm working on assigning access points to a building using a <select> element. I've created a simple controller for this task, but it's not fun ...

What is the process for retrieving input values in Angular JS?

When using Angular JS, inputs can be created. <input type="text"> <input type="text"> How can I retrieve values from each input and send them to the server? I attempted: <input type="text" ng-model="typeInput"> However, I am only abl ...

Issue with Angular 4: Radio button defaults not being set

After hardcoding the value in component.ts, I am able to see the pre-selected radio button. However, when attempting to retrieve the value from sessionStorage, it does not work as expected. The value is visible in the console though. Could someone please ...

The session data is not persisting in the express-session package

I am currently learning about HTTPS and working on implementing a login/logout function. In this function, I store the userId in the session when I login using the POST method. However, when I try to retrieve user information for the next components usin ...

Retrieve a JSON response from within a schema housed in MongoDB

I have a document structure that looks like this: { "id": "someString", "servers": [ { "name": "ServerName", "bases": [ { "name": "Base 1", "status": true }, { "name": "Base 2", ...

saving the MediaObject to Ionic's storage with the set method

I attempted to save a Media Object on ionic storage, but encountered an error message stating: "error while saving media object in storage.set" https://i.sstatic.net/5jEaQ.jpg How can I successfully save a media object using storage.set and retrieve it ...

Retrieving a json file from a local server by utilizing angularjs $http.get functionality

After fetching a JSON file from localhost, I can see the data when I console log. However, when I inject the Factory into my controller, it returns a null object. This indicates that the variable errorMessage does not receive the JSON object because the ...

Modify the attribute of numerous elements when hovering by implementing CSS transformations

I have a pair of adjacent div elements and I want to modify the background-color attribute of both when the user hovers over one of them. Initially, both divs should have a background-color set to #d8d8d8, and this color should change to #cacaca on both d ...

Discover a foolproof method for effortlessly examining an flv or mp4 file embedded within a webpage simply by

I've encountered a challenge with JavaScript. I can successfully check a flash object in a webpage when hovering over it, but I'm unsure how to achieve the same for flv or mp4 objects when either hovering over or moving away from them. Currently ...

Having trouble getting the jQuery function to update text properly

I'm curious to understand the behavior happening in this code snippet. It seems like updating the list item by clicking doesn't work as expected using the initial method. But when rearranging the JavaScript code, it displays the correct value wit ...