0

Problem:

I Cannot get correct top offset value of DOM element when page just loaded.

The project I'm working on needs to get the offsetTop value of several DOM element when the page just loaded. The reason is that I need to re-position several DOM element depends on the $window height and their initial position on the webpage. If the DOM element is all the way down the page, I want to put a fixed bar on the bottom of the page to indicate the users "there's more, but you need to scroll down to see it".

Debugging Phase:

Method I have tried:

  1. angular.element ready event and angular $viewContentLoaded event

Here is my snippet of code of getting the offsetTop of a element

angular.element(document).ready(function(){
    var elem = angular.element(document.getElementById('test-element');
    console.log(elem[0].getBoundingClientRect().top;
    console.log(elem[0].offsetTop);
    console.log(elem.offset().top);
});

and

$scope.$on('$viewContentLoaded', function(){
    var elem = angular.element(document.getElementById('test-element');
    console.log(elem[0].getBoundingClientRect().top;
    console.log(elem[0].offsetTop);
    console.log(elem.offset().top);
});

Above will all print wrong offsetTop of the element. Then I create a timeout function to test the offsetTop value of the same element, which yield the correct offset top.

$timeout(function(){
    var elem = angular.element(document.getElementById('test-element');
    console.log(elem[0].getBoundingClientRect().top;
    console.log(elem[0].offsetTop);
    console.log(elem.offset().top);       
},100);

Basically, the timeout function waits 100ms to read the top offset of the same element, whic h gives me a correct offset

Assumption:

My assumptions why this happens because:

  1. I use ngRepeat to produce a table. The content of the table is fetched from database when the page loaded.

  2. $viewContentLoaded and angular.element ready event fire before the ngRepeat render its content. That's a possible reason because when fetching offset in $viewContentLoaded/ready event function, it has no idea of the height/offset the "ngRepeat" table yet.

  3. The reason why $timeout function can get the correct top offset is that when the $timeout function execute its code, ngRepeat finishes its work and everything on the webpage is on stable state.

  4. There exists a timing between $timeout function and $viewContentLoaded/ready event that will give me correct offset value.

Questions:

  1. Is the assumption about ngRepeat/$viewContentLoaded/ready correct?

  2. What's the right way to fetch the top offset for a DOM element when the page just loaded? Or, what's the right event to fetch the correct offset?

It's a long description of the problem. I hope I made it clear. I'm sorry for any English syntax error. Thank you a lot.

Community
  • 1
  • 1
Peng
  • 434
  • 5
  • 14

2 Answers2

0

Answering #2:

getBoundingClientRect() is relative to the current scroll position and will change as the page scrolls. Hence, to see if an element is outside the current viewport, you could do something like this:

function isOffscreen(el) {
    var rect = el.getBoundingClientRect();
    return (rect.bottom > 0 || rect.bottom <= window.innerHeight);
}
Jonathon Hill
  • 3,445
  • 1
  • 33
  • 31
0

You should probably fire an event for your ngrepeat's finish, like this: https://stackoverflow.com/a/15208347/4497117

Then you could catch that exact event in your directive. This is the closest i have seen to be working (without too much clutter). Also be aware that if you have visibility toggling (ng-show) at the moment the custom ngrepeat finish event fires, you may still get weird values

Community
  • 1
  • 1
dekztah
  • 373
  • 7
  • 17