Search code examples
jqueryangularjswindowoffsetscrolltop

How do I get the offset().top value of an element without using jQuery?


I'm programming a single-page application using the Angular framework. I'm new to it. I've read this guide to help me understand the fundamental differences between jQuery and Angular and I'd like to follow this guidance as much as possible and NOT use jQuery.

Except that jQuery helps get around some of the browser incompatibilities and provides a useful library of functions, like being able to know the top position of an element from the top of the window, as in $('element').offset().top. No plain Javascript seems to be able to come close without rewriting this function, at which point wouldn't it be a better idea to use a jQuery or jQuery like library?

Specifically, what I'm trying to do is set up a directive that fixes an element in place once the top of it is scrolled to a certain position in the window. Here's what it looks like:

directives.scrollfix = function () {
    return {
        restrict: 'C',
        link: function (scope, element, $window) {

            var $page = angular.element(window)
            var $el   = element[0]
            var elScrollTopOriginal = $($el).offset().top - 40

            $page.bind('scroll', function () {

                var windowScrollTop = $page[0].pageYOffset
                var elScrollTop     = $($el).offset().top

                if ( windowScrollTop > elScrollTop - 40) {
                    elScrollTopOriginal = elScrollTop - 40
                    element.css('position', 'fixed').css('top', '40px').css('margin-left', '3px');
                }
                else if ( windowScrollTop < elScrollTopOriginal) {
                    element.css('position', 'relative').css('top', '0').css('margin-left', '0');
                }
            })

        }
    }
}

If there's a much better way to achieve this in Angular that I'm still just not getting, I'd appreciate the advice.


Solution

  • use getBoundingClientRect if $el is the actual DOM object:

    var top = $el.getBoundingClientRect().top;
    

    JSFiddle

    Fiddle will show that this will get the same value that jquery's offset top will give you

    Edit: as mentioned in comments this does not account for scrolled content, below is the code that jQuery uses

    https://github.com/jquery/jquery/blob/master/src/offset.js (5/13/2015)

    offset: function( options ) {
        //...
    
        var docElem, win, rect, doc,
            elem = this[ 0 ];
    
        if ( !elem ) {
            return;
        }
    
        rect = elem.getBoundingClientRect();
    
        // Make sure element is not hidden (display: none) or disconnected
        if ( rect.width || rect.height || elem.getClientRects().length ) {
            doc = elem.ownerDocument;
            win = getWindow( doc );
            docElem = doc.documentElement;
    
            return {
                top: rect.top + win.pageYOffset - docElem.clientTop,
                left: rect.left + win.pageXOffset - docElem.clientLeft
            };
        }
    }