How to get a callback event when an ion-item becomes visible in the ion-list?

Is there any angular directive or ion solution to get a callback when an item becomes visible in the list ?

Thanks in advance

anyone out there for any suggestions ?

could you do that? I need the same.

I was struggling a long time to find a solution. Finally I did that by manually looping through the items and checking each item’s location in the screen. This is not a great solution but didn’t find any other easy solution. I did some optimization also to reduce the looping. Here is the excerpt code -

function startProcessingMessageReadingStatus() {
            var lastItemVisibilityStatus = new MessageDisplayStatus(false, 0);
            for (var i = $scope.messagesToBeDisplayed.length - 1; i >= 0; i--) {
                if (isScrollingStarted === true) {
                    break; // quit processing message visibility as user started scrolling again
                }
                console.log('checking message : ' + i);
                var message = $scope.messagesToBeDisplayed[i];
                var isAlreadyMarkedAsRead = isMessageMarkedAsRead(message);
                if (isAlreadyMarkedAsRead === false) {
                    var visibilityStatus = isMessageItemVisible(message);
                    if (visibilityStatus.visible === true) {
                        lastItemVisibilityStatus = visibilityStatus;
                        markMessageAsRead(message);
                    } else { // item not visible
                        // check if last item above the current one was ALSO not visible, if so then better to avoid un-neccessary looping to check for visibility.
                        // Also, new message items while paginating are added on top, so only avoiding the checking of bottom elements outside the screen may be sufficient.
                        if ( (lastItemVisibilityStatus.visible === false) && (lastItemVisibilityStatus.offset > 0) && (visibilityStatus.offset > 0) && ((visibilityStatus.offset - lastItemVisibilityStatus.offset) > 0) ) {
                            lastItemVisibilityStatus = visibilityStatus;
                            console.log('Was going further below offscreen, Stopping loop at: ' + i);
                            break;
                        } else if ( (lastItemVisibilityStatus.visible === false) && (lastItemVisibilityStatus.offset < 0) && (visibilityStatus.offset < 0) && ((lastItemVisibilityStatus.offset - visibilityStatus.offset) > 0) ) {
                            lastItemVisibilityStatus = visibilityStatus;
                            console.log('Was going further top offscreen, Stopping loop at: ' + i);
                            break;
                        }
                        
                        lastItemVisibilityStatus = visibilityStatus;
                    }
                }
            }
        }



function isMessageItemVisible(message) { // this method returns an object of MessageDisplayStatus


            var item = document.getElementById('message-item-'+message.id); // each element has an id starting with 'message-item-'
            if (item === undefined) {
                return new MessageDisplayStatus(false, 0);
            }

            var scrollPosition = scrollDelegate.getScrollPosition();
            var scrollWindowHeight = scrollView.getBoundingClientRect().height;

            var itemPosition = ionic.DomUtil.getPositionInParent(item);

            var topDistance = scrollPosition.top + scrollWindowHeight;
            var itemBottom = itemPosition.top + item.getBoundingClientRect().height;


//     ------   ---------------   -----------------------------
//      /|\     |             |                          /|\
//       |      |             |                           |  --->  scrollPosition.top
//     i |      |             |                           |
//     t |      |_____________|     _____________________\|/___
//     e |      [             ]       /|\                            
//     m |      [             ]        |                             
//       |      [             ]        |                             
//     p |      [             ]        |                             
//     o |      [             ]        |                             
//     s |      [             ]        |----> scrollWindowHeight ( Scrollable  window )
//     i |      [             ]        |                             
//     t |      [             ]        |                             
//     i |      [             ]        |                             
//     o |      [_____________]     __\|/_____                       
//     n |      |             |                                      
//  ____\|/___  | ___________ |     ______                                   
//              ||  An Item  ||           \_____  itemHeight                           
//              ||___________||     ______/
//              |             |
//              |             |                        
//              --------------- 
// 
            if ((itemBottom < topDistance) && (itemPosition.top > scrollPosition.top)) {
                console.log('MessageId: ' + message.id + ' is completely visible. Text: ' + message.text.slice(0,100));
                var itemVisibilityStatus = new MessageDisplayStatus(true, null);
                return itemVisibilityStatus; 
            } else if ((itemBottom < topDistance) && ((itemPosition.top + numberOfVerticalPixelsInMessageAllowedOutsideOfVisibleArea) > scrollPosition.top)) {
                console.log('MessageId: ' + message.id + ' is almost fully visible from top : Text: ' + message.text.slice(0,50));
                var itemVisibilityStatus = new MessageDisplayStatus(true, null);
                return itemVisibilityStatus; 
            } else if ((itemBottom < topDistance) && (itemPosition.top > scrollPosition.top)) {
                console.log('MessageId: ' + message.id + ' is almost fully visible from bottom : Text: ' + message.text.slice(0,50));
                var itemVisibilityStatus = new MessageDisplayStatus(true, null);
                return itemVisibilityStatus; 
            } else if (topDistance < itemBottom) {
                var itemVisibilityStatus = new MessageDisplayStatus(false, itemBottom - topDistance);
                return itemVisibilityStatus;
            } else if (itemPosition.top < scrollPosition.top) {
                var itemVisibilityStatus = new MessageDisplayStatus(false, itemPosition.top - scrollPosition.top);
                return itemVisibilityStatus;
            } else {
                return new MessageDisplayStatus(false, 0);
            }
        }

This is a working solution but I would be looking for better performant solution. Hope this helps.

1 Like

I’ll be checking when possible, thank you so much, tushar4ic!