{"id":1786,"date":"2017-05-03T11:31:21","date_gmt":"2017-05-03T09:31:21","guid":{"rendered":"https:\/\/blog.kodono.info\/wordpress\/?p=1786"},"modified":"2022-12-08T20:08:02","modified_gmt":"2022-12-08T19:08:02","slug":"trigger-an-event-when-an-element-is-visible-in-a-scrollable-area-javascript","status":"publish","type":"post","link":"https:\/\/blog.kodono.info\/wordpress\/2017\/05\/03\/trigger-an-event-when-an-element-is-visible-in-a-scrollable-area-javascript\/","title":{"rendered":"Trigger an event when an element is visible in a scrollable area [JavaScript]"},"content":{"rendered":"<p><strong>EDIT in 2022<\/strong><\/p>\n<p>It might also be interesting to look at <a href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Intersection_Observer_API\">Intersection Observer<\/a> that is now available in most browsers, and there is also a <a href=\"https:\/\/github.com\/WICG\/IntersectionObserver\">polyfill<\/a>.<\/p>\n<pre class=\"brush:javascript\">\r\nconst observer = new IntersectionObserver((entries, observer) => {\r\n  entries.forEach((entry) => {\r\n    let isVisible=(entry.intersectionRatio===1);\r\n  });\r\n}, {threshold:1});\r\nobserver.observe(document.querySelector('#element');\r\n<\/pre>\n<p><strong>END EDIT<\/strong><\/p>\n<p>I have this specific need that is to trigger an event when an element becomes visible\/invisible into a scrollable area. Here is the code I came to:<\/p>\n<pre class=\"brush:javascript\">\r\n\/**\r\n * Create the handler\r\n * @param {NodeElement} holder The scrollable area to monitor (where the 'scroll' event will be apply)\r\n *\/\r\nvar VisibleEventListener = function(holder) {\r\n  var _this=this;\r\n  _this.started = false;\r\n  _this.holder = holder;\r\n  \/\/ detect if an element is visible\r\n  _this.isScrolledIntoView=function(el) {\r\n    var bndElem = el.getBoundingClientRect();\r\n    var bndHolder = _this.holder.getBoundingClientRect();\r\n    return bndElem.top &lt;= bndHolder.top ? !(bndHolder.top - bndElem.top > bndElem.height) : !(bndElem.bottom - bndHolder.bottom > bndElem.height);\r\n  }\r\n  \/\/ permits to deal with the scroll\r\n  _this.scrollHandler=function(e) {\r\n    for (var i=0, len=_this.events.length; i&lt;len; i++) {\r\n      _this.events[i].check();\r\n    }\r\n  }\r\n  _this.events=[];\r\n}\r\n\/**\r\n * Add the visible\/invisible event for an element into a scrollable area\r\n * @param {NodeElement}   element  The element to test\r\n * @param {String}   listener 'visible' or 'invisible'\r\n * @param {Function} callback The callback function to be called when the event is triggered\r\n *\/\r\nVisibleEventListener.prototype.add = function(element, listener, callback) {\r\n  var _this=this;\r\n  var ElementToMonitor=function(element, listener, callback) {\r\n    this._super=_this;\r\n    this.element=element;\r\n    this.isVisible=false;\r\n    this.callback=callback;\r\n    this.listener=listener;\r\n  }\r\n  ElementToMonitor.prototype.check = function() {\r\n    var visible=this._super.isScrolledIntoView(this.element);\r\n    if (visible &#038;& !this.isVisible) { \/\/ becomes visible\r\n      this.isVisible=true;\r\n      if (this.listener==='visible') this.callback.call(this.element)\r\n    } else if (!visible &#038;& this.isVisible) { \/\/ becomes invisible\r\n      this.isVisible=false;\r\n      if (this.listener==='invisible') this.callback.call(this.element)\r\n    }\r\n  };\r\n  var etm=new ElementToMonitor(element,listener,callback);\r\n  _this.events.push(etm);\r\n  \/\/ if we have started to monitor\r\n  if (_this.started===true) etm.check();\r\n}\r\nVisibleEventListener.prototype.start = function() {\r\n  this.holder.addEventListener('scroll', this.scrollHandler);\r\n  this.started = true;\r\n  \/\/ trigger the check to verify if the elements are already visible\r\n  this.scrollHandler();\r\n}\r\nVisibleEventListener.prototype.stop = function() {\r\n  this.holder.removeEventListener('scroll', this.scrollHandler);\r\n  this.started = false;\r\n}\r\n<\/pre>\n<p>And to use it:<\/p>\n<pre class=\"brush:javascript\">\r\n\/\/ initiate our area with VisibleEventListener\r\nvar vel = new VisibleEventListener(document.querySelector('#s4-workspace'));\r\n\/\/ add the elements to monitor\r\nvel.add(document.querySelector('.slideshow'), 'invisible', function() {\r\n  console.log(this,' is now invisible')\r\n})\r\nvel.add(document.querySelector('.slideshow'), 'visible', function() {\r\n  console.log(this,' is now visible')\r\n})\r\n\/\/ start the monitoring\r\nvel.start();\r\n<\/pre>\n","protected":false},"excerpt":{"rendered":"<p>EDIT in 2022 It might also be interesting to look at Intersection Observer that is now available in most browsers, and there is also a polyfill. const observer = new IntersectionObserver((entries, observer) => { entries.forEach((entry) => { let isVisible=(entry.intersectionRatio===1); }); }, {threshold:1}); observer.observe(document.querySelector(&#8216;#element&#8217;); END EDIT I have this specific need that is to trigger an [&hellip;]<\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_coblocks_attr":"","_coblocks_dimensions":"","_coblocks_responsive_height":"","_coblocks_accordion_ie_support":"","hide_page_title":"","footnotes":""},"categories":[170,13,33],"tags":[123,24,152,158],"class_list":["post-1786","post","type-post","status-publish","format-standard","hentry","category-english","category-niveau-intermediaire","category-programmation","tag-english","tag-javascript","tag-niveau-intermediaire","tag-programmation"],"_links":{"self":[{"href":"https:\/\/blog.kodono.info\/wordpress\/wp-json\/wp\/v2\/posts\/1786","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/blog.kodono.info\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/blog.kodono.info\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/blog.kodono.info\/wordpress\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/blog.kodono.info\/wordpress\/wp-json\/wp\/v2\/comments?post=1786"}],"version-history":[{"count":7,"href":"https:\/\/blog.kodono.info\/wordpress\/wp-json\/wp\/v2\/posts\/1786\/revisions"}],"predecessor-version":[{"id":2200,"href":"https:\/\/blog.kodono.info\/wordpress\/wp-json\/wp\/v2\/posts\/1786\/revisions\/2200"}],"wp:attachment":[{"href":"https:\/\/blog.kodono.info\/wordpress\/wp-json\/wp\/v2\/media?parent=1786"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/blog.kodono.info\/wordpress\/wp-json\/wp\/v2\/categories?post=1786"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/blog.kodono.info\/wordpress\/wp-json\/wp\/v2\/tags?post=1786"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}