angular-inview icon indicating copy to clipboard operation
angular-inview copied to clipboard

Detect active tab

Open dbrgn opened this issue 8 years ago • 6 comments

Is there a way for inview to detect whether the object is actually visible?

I'm pretty sure there's no way to know whether another window obstructs the visibility, but maybe there's a way to know whether the tab is actually active, or whether another tab of the same window is opened.

Here are some resources that might help: https://stackoverflow.com/questions/1760250/how-to-tell-if-browser-tab-is-active

dbrgn avatar Sep 27 '16 11:09 dbrgn

there is for sure a way to detect if a window/tab is active. how would you see this fit for this directive though? Could you give a code example of how you'd use the directive?

thenikso avatar Sep 28 '16 14:09 thenikso

I see different possibilities. Either a separate attribute:

<div in-view="$inview && ctrl.isVisible()" strict-visibility="true"></div>

Or an attribute on $inviewInfo:

<div in-view="$inview && $inviewInfo.hasFocus && ctrl.isVisible()"></div>

In any case it would mean that inview would have to trigger a change event if the tab/window focus changes. If you don't want to do that by default for perforamnce reasons, maybe that could be implemented as a configuration, either via attribute or using a provider.

It would certainly be useful if inview would detect focus, as some things don't need to be done if the window is not focused, saving energy on mobile devices. Another use case is "read notifications" if a user looks at a certain element. If a window is out of focus, a read notification should not be triggered, even if the object is inside the viewport.

dbrgn avatar Sep 28 '16 15:09 dbrgn

Perhaps you could apply it to the in-view-container. In this case the container would be the tab, and so, if specified, you check to see if the container is visible?

Also, using the ClientRect is a pretty good heuristic for whether the element is truly visible. If all it's values are 0 (i.e. it's right at the top of the screen with 0 width and height) then it's quite likely to not really be visible.

vm.initIfVisible = $inviewInfo => {
  let rect = $inviewInfo.elementRect,
      keys = ['height', 'width', 'top', 'bottom', 'left', 'right'],
      isVisible = keys.map(key => rect[key]).some(value => value > 0);

  if(isVisible) {
    vm.init();
  }
};

However this still doesn't work nicely because interactions with tabs occur on click events, not scroll. So you'd need to also have a click listener which triggered another check. For that reason you'd almost certainly want to have this as an optional directive / option.

Alternatively you can also use $inviewInfo.element[0].offsetParent - but again, you won't know when to initialise it after clicking the tab.

evenicoulddoit avatar Nov 11 '16 14:11 evenicoulddoit

So after looking at this a little more, hopefully I have a solution (above).

Adding the requireOffsetParent to in-view-options should address the issue by only regarding an element as in view if it both overlaps with the viewport boundingRect and it has an offsetParent.

I chose not to make it the default behaviour because:

  • An offsetParent is never reported for a fixed positioned element - you'd need to make additional checks for it
  • Putting it behind an optional flag is safer as I don't know all the nuances of when it should normally trigger

evenicoulddoit avatar Nov 11 '16 17:11 evenicoulddoit

Regarding this issue: Checking for document.hidden === false and/or document.visibilityState === 'visible' should suffice.

https://developer.mozilla.org/en-US/docs/Web/API/Page_Visibility_API

I'll give it a stab, but might need your help.

dbrgn avatar Mar 07 '17 09:03 dbrgn

A fix for this is waiting in #122. Any chance to get that merged?

We're using angular-inview in Threema Web, where the ability to detect active tabs would help to improve usability.

dbrgn avatar Apr 20 '17 09:04 dbrgn