davidjbradshaw / iframe-resizer

Keep iFrames sized to their content.

Home Page:https://iframe-resizer.com

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

heightCalculationMethod on nuxt

rustynail1984 opened this issue · comments

im trying to use the heightCalculationMethod: 'taggedElement' option on nuxt

My iframe page:

<iframe
      v-resize="{ log: true, heightCalculationMethod: 'taggedElement'}"
      :id="iframeId"
      :src="PreUrl"
      width="100%"
      height="100%"
      allowtransparency="true"
      scrolling="no"
      style="border: none">
</iframe>
<script>
...

directives: {
    resize: {
      bind(el, { value = {} }) {
        el.addEventListener("load", () => iframeResize(value, el));
      },
    },
 },
<script>

My Content Page:

<template>
<div>
  <div class="flex flex-wrap place-content-center gap-4 justify-center mx-auto p-2" data-iframe-height>
    <SearchCard v-for="s in search" :key="s.key" :data="s"/>
  </div>
</div>
</template>

Browser Console:
iframeResizer.contentWindow.js:170 [iFrameSizer][searchApi] No tagged elements (data-iframe-height) found on page

Someone has an idea why data-iframe-height is not found?

im trying to use the heightCalculationMethod: 'taggedElement' option on nuxt

My iframe page:

<iframe
      v-resize="{ log: true, heightCalculationMethod: 'taggedElement'}"
      :id="iframeId"
      :src="PreUrl"
      width="100%"
      height="100%"
      allowtransparency="true"
      scrolling="no"
      style="border: none">
</iframe>
<script>
...

directives: {
    resize: {
      bind(el, { value = {} }) {
        el.addEventListener("load", () => iframeResize(value, el));
      },
    },
 },
<script>

My Content Page:

<template>
<div>
  <div class="flex flex-wrap place-content-center gap-4 justify-center mx-auto p-2" data-iframe-height>
    <SearchCard v-for="s in search" :key="s.key" :data="s"/>
  </div>
</div>
</template>

Browser Console: iframeResizer.contentWindow.js:170 [iFrameSizer][searchApi] No tagged elements (data-iframe-height) found on page

Someone has an idea why data-iframe-height is not found?

have you found any solutions?

have you found any solutions?

nope

I'm afraid I never used Nuxt. This might be more a question for StackOverflow

unfortunately the package needs a bit of improvement for the taggedElement behavior. It stops when it cannot find a taggedElement but in the case of JS frameworks, elements rendered on the page may not be available the time iFrameResizer calls resize but some milliseconds later.

I ended up implementing a retry mechanism. it is not reliable, as the time it takes to render the element on JS frameworks varies and also it keeps calling resize until timeout is reached so if the taggedElement is found earlier, you end up calling resize redundantly, but it handles my use cases.

the code looks somewhat like this, adapt to your own use case:

resizerResizeInterval: number | undefined = undefined
resizerResizeIntervalIteration: number = 0
resizerResizeIntervalTimeout: number = 1000
resizerResizeIntervalIterationTimer: number = 50

tryResize(iframe: HTMLIFrameElement) {
    this.resizerResizeInterval = setInterval(() => {
        if (
            this.resizerResizeIntervalIteration *
                this.resizerResizeIntervalIterationTimer >=
            this.resizerResizeIntervalTimeout
        ) {
            clearInterval(this.resizerResizeInterval)
            this.resizerResizeInterval = undefined
            ;(iframe as any).iFrameResizer?.resize()
        } else {
            ;(iframe as any).iFrameResizer?.resize()
            this.resizerResizeIntervalIteration += 1
        }
    }, this.resizerResizeIntervalIterationTimer) as unknown as number
}

it is worth mentioning that, this retry mechanism, in my opinion, should be built in the package itself. maybe it already does through the MutationObserver but in the case of taggedElement strategy, I don't see any logs/warnings being printed when MutationObserver triggers resize, I don't see "No tagged elements" being printed more than one time. This may be a bug or just lack of a retry mechanism.

Alternatively if it is not desired to add such retry mechanism to the package, we would need event callbacks while initializing the iFrameResizer, something along the lines of:

onTaggedElementFound: () => {},
onTaggedElementNotFound: () => {}

I have solved the issue temporarily to save the day and I'm highly sure that the unreliable timeouts etc will cause an issue next week on some of the iframes therefore I'll try to help by adding the above callbacks to the package through a PR so that we can do:

pseudo code:

const stopPolling = () => {
    //remove interval
}

const startPolling = (iframe) => {
   if timeout reached
      stopPolling()
   else
      keep calling iframe.iFrameResizer.resize()
}

onTaggedElementNotFound: () => {
   startPolling()
},
onTaggedElementFound: () => {
   stopPolling()
}

We can hack console.warning (not desired at all and not scalable if later someone decides to change the console warning to a console log or the message being printed) by proxying it to see if a log with "No tagged elements" is printed in the console to detect not found behavior already but the package does not print a log message when it finds the tagged element so we cannot hack the found behavior through the console (I guess unless we turn on logs printed by the package, which is again not desired as it prints tons of logs and it would not be ideal in a production environment)

Would it not be simpler just to make sure you have a tagged element in the page template?

just as a follow up, I've revised the implementation to be more robust. I unfortunately don't have code snippets to share but it works like this:

In React (or any other framework), high up in the component tree, I have an interval that keeps checking whether the tagged element with data-iframe-height has actually been mounted:

const intervalId = setInterval(() => {
    const el = document.querySelector(
        "[data-iframe-height]",
    )

   if (el) {
      //send window.postMessage event to the parent that element has bee mounted
     clearInterval(intervalId)
   }
}, 100)

Then in the parent I am listening to message events:

window.addEventListener('message', (message) => {
    //check if message is originating from inside of the iframe
    //and call iframe.iFrameResizer.resize()
})