Morpheus Morpheus - 7 months ago 295
Javascript Question

javascript getBoundingClientRect() values are wrong for dynamically added elements

Not able to find an answer on wide web so posting the question here.

What I am trying to achieve:

When the user scrolls to the very bottom of the page get the latest dynamically loaded element's bottom value and use it to find out if it is time to load another one.

The math is simple:

if (element.getBoundingClientRect().bottom <= window.innerHeight)
loadAnotherElement();



window.innerHeight is 955px


The problem:

On initial load the the first element's bottom value is
905px
which is fine and trigger the function to load another one, but after the second one is loaded in the bottom value is
1389px
which will never trigger the
loadAnotherElement
function.

I am not able to post full code as it is too complicated so hope the above will be enough to understand.

EDIT

Managed to create a proper test case

Answer

In the JS fiddle you posted the reason it was not recognising the correct height is because your inner elements are floating. A float does not contribute to the height of the parent element, so I will suggest the following solution:

article:after {
    width: 100%;
    clear: both;
    content: '';
    display: block;
}

I have also cleaned up the fiddle a bit an removed the unnecessary parts so it's easier to see where the mistake was (there was no advantage to the table style displayed before and after on your section).

var last = document.querySelector('article');
document.addEventListener('scroll', function(){
    if(last.getBoundingClientRect().bottom <= window.innerHeight){
        var newElement = last.cloneNode(true);
        last.parentNode.appendChild(newElement);
        last = newElement;
    }
});
html,
body {
    height: 100%;
}

/* I have removed a bit of CSS that I think didn't really do anything at all. */

article {
    width: 100%;
    display: inline-block;
    border-bottom: 1px solid red;
}

/* This will create an element that will clear past the floats, stretching your article to the correct encapsulating size */

article:after {
    width: 100%;
    clear: both;
    content: '';
    display: block;
}

/* Some correction so they all stay neatly in line */

div {
    float: left;
    width: 30%;
    margin: 1.5%;
    height: 100vh;
    position: relative;
    background: blue;
}

div:nth-child(3n-2){ background: #666; }
div:nth-child(3n-1){ background: #888;  }
div:nth-child(3n){ background: #222; }
<section>
  <article>
    <!-- I made these 6 divs so they neatly pack six in an article. -->
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </article>
</section>

Update

If you want the elements to neatly stay in line, why bother wrapping them in seperate elements? Simple create the elements as new siblings which will push its final size:

var section = document.querySelector('section');
var article = document.querySelector('article');
document.addEventListener('scroll', function(){
    if(section.getBoundingClientRect().bottom <= window.innerHeight){
        section.appendChild(article.cloneNode(true));
    }
});
html,
body {
    height: 100%;
}

/* I have removed a bit of CSS that I think didn't really do anything at all. */

section {
    width: 100%;
    display: inline-block;
    border-bottom: 1px solid red;
}

/* This will create an element that will clear past the floats, stretching your article to the correct encapsulating size */

section:after {
    width: 100%;
    clear: both;
    content: '';
    display: block;
}

/* Some correction so they all stay neatly in line */

div {
    float: left;
    width: 30%;
    margin: 1.5%;
    height: 100vh;
    position: relative;
    background: blue;
}

div:nth-child(3n-2){ background: #666; }
div:nth-child(3n-1){ background: #888;  }
div:nth-child(3n){ background: #222; }
<section>
  <article>
    <!-- I made these 7 divs for illustrations sake. -->
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
    <div></div>
  </article>
</section>

Comments