1

I have one page which contains Iframe, iframe has few elements that need to be loaded only if it's in viewport.

But iframe is not scrollable, only master page has scroll. I have written following function but its not working if used with master page.

function isVisible(a) {
        var b1 = a.getBoundingClientRect(),
        b={},
        c = window.innerWidth || doc.documentElement.clientWidth,
        d = window.innerHeight || doc.documentElement.clientHeight,
        e = function(a, b) {
            return document.elementFromPoint(a, b)
        };
        if(window.frameElement){
            var w = window.frameElement.getBoundingClientRect();
        //  d = window.innerHeight || doc.documentElement.clientHeight;
            for( var i in b1){
              b[i]=Math.abs(b1[i])+Math.abs(w[i])
            }
        }else{
            b=b1;
        }
    return !(b.right < 0 || b.bottom < 0 || b.left > c || b.top > d) && (a.contains(e(b.left, b.top)) || a.contains(e(b.right, b.top)) || a.contains(e(b.right, b.bottom)) || a.contains(e(b.left, b.bottom)))
}

Please suggest a way forward, thanks in advance .

Shrijan Tiwari
  • 673
  • 6
  • 17

1 Answers1

0

This will defer loading of the iframe content until it is scrolled into view.

JSFiddle Example

var $iframe = $("#iframe");
$(window).on("scroll", function() {
  // you should probably throttle or debounce this method; I didn't
  if (isScrolledIntoView($iframe[0])) {
     // assumes same origin for iframe
     // if iframe has window object and function "viewportUpdate" call function
     var iframeWindow = $iframe[0].contentWindow;         
     if (iframeWindow && iframeWindow.viewportUpdate)
     {
         var docViewTop = $(window).scrollTop();
         var docViewBottom = docViewTop + $(window).height();
         iframeWindow.viewportUpdate(docViewTop, docViewBottom);
     }
  }
});

// from http://stackoverflow.com/questions/487073/check-if-element-is-visible-after-scrolling
function isScrolledIntoView(elem) {
  var docViewTop = $(window).scrollTop();
  var docViewBottom = docViewTop + $(window).height();

  var elemTop = $(elem).offset().top;
  var elemBottom = elemTop + $(elem).height();

  return ((elemBottom <= docViewBottom) && (elemTop >= docViewTop));
}

iframe content uses this method to do your magic:

function viewportUpdate(docViewTop, docViewBottom)
{
   // do your magic here.. whatever that is
   // for example, loop over each "img" element and log to console if in view
   $("img").each(function()
   {
       var elemTop = $(elem).offset().top;
       var elemBottom = elemTop + $(elem).height();
       var elementIsInView = (elemBottom <= docViewBottom) && (elemTop >= docViewTop);
       if (elementIsInView)
       {
           console.log("iframe img element is in view");
       }
   });
}
nothingisnecessary
  • 6,099
  • 36
  • 60
  • 1
    I am looking to defer loading of internal content of iframe. This code defers loading of an iframe element itself. – Shrijan Tiwari Mar 26 '17 at 09:22
  • Do you own the content inside iframe or is it hosted by somebody else? What use case? – nothingisnecessary Mar 27 '17 at 19:24
  • content is owned by us only and in same domain – Shrijan Tiwari Mar 28 '17 at 07:51
  • then extend answer to your `iframe` content: first parent page checks if `iframe` is in view, and calls function in iframe (use `postMessage` if you ever do need cross origin). The function in the `iframe` can take as parameters the viewport boundaries of the parent page and then do additional checking for elements inside the `iframe`. see updated answer for basics. This could get pretty weird pretty quick tho, and doesn't work well on iOS because it hates iframes and scrolling. If you tell us the specific user problem you are trying to solve we may be able to suggest a better approach. – nothingisnecessary Mar 28 '17 at 18:05