2

I have scenario where I implemented a datatable with in a lightning component with scrollable y axis. Now the challenge is there are two scroll bars. One for lightning component and another one for entire window.

  1. I need to implement infinite loading for lightning component.
  2. What is the best way to detect scroll event when there are multiple scroll bars.

Any Pointers? Thanks in Advance.

1

Thanks Mohit and Lieven


 ({
        afterRender : function( component, helper ) {
            this.superAfterRender();
            var didScrolled;
            var div = component.find('scroll_container');
            if(!$A.util.isEmpty(div)){
                div = div.getElement();
                div.onscroll = function(){
                    didScrolled = true;
                    };
                //Interval function to check if the user scrolled or if there is a scrollbar
                var intervalId = setInterval($A.getCallback(function(){
                    if(didScrolled){
                        didScrolled = false;
                        if(div.scrollTop === (div.scrollHeight - div.offsetHeight)){
                            helper.getNextPage(component);
                        }
                    }
                }), 750);
                component.set('v.intervalId', intervalId);
            }
        },
        unrender: function( component) {
            this.superUnrender();
            var intervalId = component.get( 'v.intervalId' );
            if ( !$A.util.isUndefinedOrNull( intervalId ) ) {
                window.clearInterval( intervalId );
            }
        }
    })
0

I had a similar requirement but with just the two scrollbars, one for the table and another for the whole window.

To capture the scroll event:

Use <tbody onscroll="{!c.scrollBottom}">

You'll have to use obj.scrollTop, obj.scrollHeight obj.offsetHeight to know the position of the scrollbar. On your scrollBottom method, create console.log for all three and notice their values when the scrollbar has reached the bottom.

More: https://stackoverflow.com/questions/876115/how-can-i-determine-if-a-div-is-scrolled-to-the-bottom

To add new elements to the list:

fetch the remaining records when you reach the bottom and add them to the recordsToShow and set the attribute. The list will automatically reflect.

0

What you can do is subscribe to the onscroll element of your datatable element or the element that has the scrollable y assigned to it.

For one of my projects I implemented a similar use-case as the one you have. I wrote a component that contains a scrollable div. On that div i'm subscribing to the onscroll event. When the div is being scrolled I send out a component event to notify the component that might be interested. For example the 'smart' component that is responsible for loading in additional data.

Subscribing to the onscroll event is done best in the renderer on afterRender. This is the core logic of detecting a scroll event. Note that I'm using in interval function to notify if the div was scrolled. If this isn't applied the component could sent out quite a few scroll event.

afterRender : function(cmp,helper)
{
    this.superAfterRender();

    /*
        We are not handling this with a controller method as that might be a performance pitfall.
        Instead we are using the mechanism described in this blog post:
        https://johnresig.com/blog/learning-from-twitter/
        This avoids loading getting called on every scroll event. One scroll with the mouse wheel can trigger quite a few
        events which will all trigger lightning. No need to say this can be a hazard for performance.
        Instead we are add a listener to the div container and are setting a variable to true; That's all the logic
        that is executed outside a lightning cycle.
        Every x miliseconds we check if a scroll was done and only then we execute our logic.
        This will make sure the scrolling remains smooth as no logic has to be executed for every scroll.

        Logic is added to the afterRender because on init the div element is not yet added to the page.
    */

    var scrolled;//Variable that will be bound to the onscroll function and interval function to check if the user has scrolled
    var div = cmp.find('scroll_container');
    if(!$A.util.isEmpty(div))
    {
        div = div.getElement();
        div.onscroll = function(){
            scrolled = true;
        }

        var noScroll = false;//Determines if there is a scrollbar or not.

        //Interval function to check if the user scrolled or if there is a scrollbar
        var intervalId = setInterval($A.getCallback(function(){
            if(scrolled) //The user scrolled so handle the scroll logic
            {
                scrolled = false;
                helper.handleContainerScrolled(cmp);
            }
            else
            {
                if(!(div.clientHeight < div.scrollHeight) && !noScroll)//There is no scrollbar and it is the first time
                {
                    noScroll = true;
                    var sEvent = cmp.getEvent('scrolled');
                    sEvent.fire();
                }
                else if((div.clientHeight < div.scrollHeight))//There is a scroll bar
                {
                    noScroll = false;
                }
            }
        }),750);
        cmp.set('v.intervalId',intervalId);
    }
},

unrender: function( component, helper ) {

    this.superUnrender();

    // Since setInterval() will be called even after component is destroyed
    // we need to remove it in the unrender
    window.clearInterval( component.get( "v.intervalId" ) );
}

Once you have the core going you can simply define when you want to send the scroll event. For example in my case I want to send an event when the scrollbar has surpassed a certain threshold (near the end)

  • Thanks guys, I was able to solve the issue with a combination of solutions you both provided. – salesforcefdev Aug 28 '17 at 16:36
  • I'm doing something similar, trying to detect when a user has scrolled to the bottom of a div. Just wondering what "component.get( "v.intervalId" )" represents here? What kind of attribute is that? – Aislinn Hayes Aug 28 '18 at 15:52
  • @AislinnHayes the intervalId is integer I believe just to hold the time interval to capture the legit scroll event rather than handling every scroll event. – salesforcefdev Oct 8 '18 at 4:45
  • Thanks! Managed to find the definition for this on some Javascript docs: w3schools.com/jsref/met_win_setinterval.asp Return Value: A Number, representing the ID value of the timer that is set. Use this value with the clearInterval() method to cancel the timer – Aislinn Hayes Oct 8 '18 at 13:16

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.