Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I get the x and y positions of an element in an AngularJS directive

Within the link function part of a directive we have access to the element object. I wish to determine if the element object is within the current viewport / if it is available.

I currently have the following:

link: function (scope, element, attrs, controller) {


                var page = angular.element(window);
                page.bind('scroll', function () {
                   var windowScroll = page[0].pageYOffset,
                       windowHeight = page[0].innerHeight;
                       // elementScroll = element.xpos; - this is undefined?
                       // elementScroll = element.getBoundingClientRect().top - this does not work... undefined?

                       // elementScroll = element[0].getBoundingClientRect().top - this does not work... undefined?
                       // ... logic follows that if elementScroll is between windowScroll & windowScroll + windowHeight it is visible!

                });

I just can't seem to get the x and y positions for my specific element (the directive may be repeated many times).

Please note that I do not intend to install or use jQuery in my application.

like image 413
Mark Sandman Avatar asked Jun 11 '14 15:06

Mark Sandman


People also ask

Which directive is used to assign values to the variables in AngularJS?

ng-init directive It is used to declare and assign values to the variables for an AngularJS application.

Which of the directive is used to display text in AngularJS?

ng-app: The ng-app Directive in AngularJS is used to define the root element of an AngularJS application. This directive automatically initializes the AngularJS application on page load. It can be used to load various modules in AngularJS Application.

What is scope in AngularJS directive?

Scope in a Directive Well, all of the directives have a scope associated with them. This scope object is used for accessing the variables and functions defined in the AngularJS controllers, and the controller and link functions of the directive.

Which directive do we use to inform AngularJS about the parts controlled by it?

The ngRef attribute tells AngularJS to assign the controller of a component (or a directive) to the given property in the current scope. It is also possible to add the jqlite-wrapped DOM element to the scope. The ngRepeat directive instantiates a template once per item from a collection.


1 Answers

You can use element[0].getBoundingClientRect, it works - there is an example:

http://plnkr.co/edit/2eOw3B0MaM2vw3bQuFnf

If you need to track element visibility in angular directive, except scroll you also need to handle events: DOMContentLoaded, load and resize. Also it would be better to create only one handler for those events, and stop tracking element when directive is destroyed

app.directive('trackVisibility', function(){
  function isVisible(el) {
    var rect = el.getBoundingClientRect();
    var clw = (window.innerWidth || document.documentElement.clientWidth);
    var clh = (window.innerHeight || document.documentElement.clientHeight) ;

    // checks if element is fully visible
    //return (rect.top >= 0 && rect.bottom <= clh) && (rect.left >= 0 && rect.right <= clw);

    // checks if part of element is visible
    return (rect.left <= clw && 0 <= rect.right && rect.top <= clh && 0 <= rect.bottom);

  }
  var reg = [];

  function register(element, fn) {
    reg.push([element, fn]);
  }

  function deregister(element) {
    reg = angular.filter(reg, function (item) {
      return item[0] !== element;
    });
  }

  angular.element(window).on('DOMContentLoaded load resize scroll', function () {
    angular.forEach(reg, function (item) {
        item[1](isVisible(item[0]));
    });
  });

  return {
    restrict: 'A',
    link: function (scope, element, attrs, controller) {
      register(element[0], function(isVisible){
        scope.$apply(function(){
          scope.isVisible = isVisible;
        })
      });
      scope.$on('$destroy', function(){
        deregister(element);
      })
    }
  };
});

there is an example: http://plnkr.co/edit/VkCgBvGnCWZ0JCM8tlaJ

I have used this approach to dynamically load images when they become visible.

like image 50
Bogdan Savluk Avatar answered Oct 07 '22 16:10

Bogdan Savluk