iframe-resizer
iframe-resizer copied to clipboard
single page app inside as the iframe height not working
When using the settings:
iFrameResize({ checkOrigin: false, log: true, heightCalculationMethod: 'lowestElement' }, ".xyz-form");
any value used for heightCalculationMethod does not seem to work when using a spa app. is this possible to use with spa apps?
thanks.
Do you mean your main app is a single page app and you are trying to use an iframe, or you are loading a single page app into the iframe?
If the first case, I'm using this library in my single page app (Svelte) so it definitely can work, but I don't see why the 2nd case wouldn't work either.
Remember that the iframe itself needs to use iframeResizer.contentWindow.min.js in order for the library to work. You can copy that file from the /node_modules/iframe-resizer/js folder to somewhere the iframe can access it. This file would not be bundled with your main single page app. This is needed because the library uses postMessage between the main window and the iframe to handle the resizing.
As an example - this is my IFrame Svelte component I created which takes a plain text or html string and displays it in an iframe using iframe-resizer. Hope this helps get you on the right track.
Using Svelte 3.50.1 and iframe-resizer 4.3.2.
IFrame.svelte
<script>
import { createEventDispatcher, onDestroy } from "svelte";
import { iframeResize } from "iframe-resizer";
export let srcdoc;
export let title;
export let isText = false;
export const functions = {
getIframeElem: () => {
return elem;
},
isLoaded: () => {
return iframeLoaded;
},
};
const dispatch = createEventDispatcher();
let elem;
let iframeLoaded = false;
function handleIFrameLoaded(e) {
let doc = elem.contentDocument;
let docBody = elem.contentDocument.body;
// Set styles
docBody.style.margin = "0";
docBody.style.fontFamily = 'Roboto';
if (isText) {
docBody.style.whiteSpace = "pre-wrap";
} else {
// Set all anchor tags to open in new window
let anchorTags = docBody.querySelectorAll("a");
for (let i = 0; i < anchorTags.length; ++i) {
anchorTags[i].setAttribute("target", "_blank");
}
}
// Add iframeResizer.contentWindow.min.js script to iframe
let scriptElem = doc.createElement("script");
scriptElem.type = "text/javascript";
scriptElem.src = "/vendor/iframe-resizer/iframeResizer.contentWindow.min.js";
docBody.appendChild(scriptElem);
// Start iFrameResize
let thisDomain = window.location.protocol + "//" + window.location.hostname;
if (window.location.port != "") {
thisDomain += ":" + window.location.port;
}
iframeResize(
{
checkOrigin: [thisDomain],
heightCalculationMethod: "lowestElement",
onInit: handleIFrameResizeReady,
},
elem
);
}
onDestroy(function () {
// Cleanup iFrameResize
if (elem.iFrameResizer) {
elem.iFrameResizer.removeListeners();
}
});
function handleIFrameResizeReady(e) {
iframeLoaded = true;
elem.style.display = "";
elem.iFrameResizer.resize();
dispatch("load");
}
function escapeHtml(html) {
let temp = document.createElement('div');
temp.innerText = html;
return temp.innerHTML || '';
}
</script>
{#if !iframeLoaded && srcdoc !== undefined && srcdoc !== null}
<div class="p-6 text-center flex items-center justify-center">
<div class="spinner" />
<h3 class="mt-2 text-sm font-medium text-gray-600">Loading content...</h3>
</div>
{/if}
<iframe
{title}
srcdoc={isText ? escapeHtml(srcdoc) : srcdoc}
on:load={handleIFrameLoaded}
bind:this={elem}
style="width: 1px; min-width: 100%; height: 0; display: none"
scrolling="no" />
And used like so:
MyPage.svelte
<script>
import IFrame from "./IFrame.svelte";
let iframeFunctions;
let htmlContent = '<div style="height: 400px; border: 1px solid black; background-color: yellow;">This content appears inside the iframe</div>';
function handleIframeLoaded() {
console.log('iframe loaded, the iframe elem:', iframeFunctions.getIframeElem());
}
</script>
<IFrame
title="Content"
bind:functions={iframeFunctions}
srcdoc={htmlContent}
on:load={handleIframeLoaded} />
@fitprotracker I was having similar issues and I found that having height: 100% css on the body tag in the iframe screwed up the height calculation. I created a div inside the body with the 100% height then mounted my SPA within that. Once I did that I put iframe-resizer back to the default calculation method and everything worked out fine.
<!DOCTYPE html>
<html lang="en" class="h-full bg-white">
<head>
...
</head>
<body class="text-black">
<div class="h-full" id="app">
// mount SPA app here
</div>
</body>
</html>
dose any one find solution to this issue ?
Just found out that iFrameResizer has problems if the iFrame is reducing his size. Expanding works fine.
Let's take a pagination as an example. If the first page has 12 items and the second page only the remaining 2 items the iFrame should be less high. In my tests the document object of the iFrame was at least the last height set of his DOM iFrame element.
The solution is to use heightCalculationMethod: "taggedElement" and implement at the lowest possible point <div data-iframe-height></div>
In case of my Nuxt app:
<template>
<v-app>
<v-main>
<v-container fluid>
<slot />
</v-container>
<!--
IMPORTANT iframesizer hack. Needs to be inside v-main and not v-app.
V-app will adapt to iFrame height. heightCalculationMethod: "taggedElement"
-->
<div data-iframe-height></div>
</v-main>
</v-app>
</template>
Hope this helps and saves someone hours of debugging😊
Downsizing issues are caused by element in the iframe having percentage heights on them.