Monitor the completion of the scrollTo action

My webpage contains a scrollable element. Additionally, I have a function in place that allows me to scroll to a specific position within this element. Now, I am looking for a way to trigger another function once the scrolling action is completed.

Check out this example on Plunker

var x = document.querySelector('.container');
$scope.scrollTo = function() {
  x.scrollTo({
    top: 300 ,
    behavior: 'smooth'
  });
};

 // Implement logic here to execute when scrollTo is finished

Answer №1

By monitoring the position of the element I am scrolling to and comparing it with the current scroll position of the container, I can determine when the scrolling process is completed.

function checkScrollCompletion() {
        const checkIfScrollToIsFinished = setInterval(() => {
            if (positionOfItem === scrollContainer.scrollTop) {
                // perform an action
                clearInterval(checkIfScrollToIsFinished);
            }
        }, 25);
}

This interval function continuously checks whether the scroll position matches the desired element's position before executing an action and stopping the interval.

Answer №2

Make sure to verify that the scrolling has stopped.

With fewer parameters, no risks involved, and effective for extreme positions.

let currentPosition = null
const checkScrollStatic = setInterval(() => {
  if (currentPosition === window.scrollY) {
    clearInterval(checkScrollStatic)
    // take action here
  }
  currentPosition = window.scrollY
}, 50)

Answer №3

I adapted the solution provided by @DoiDor to guarantee that the position is rounded and added a timeout fallback as a precaution. Without this adjustment, the exact position may never be reached causing the promise to never resolve.

async function scrollToPosition(container, position) {
  position = Math.round(position);

  if (container.scrollTop === position) {
    return;
  }

  let resolveFn;
  let scrollListener;
  let timeoutId;

  const promise = new Promise(resolve => {
    resolveFn = resolve;
  });

  const finished = () => {
    container.removeEventListener('scroll', scrollListener);
    resolveFn();
  };

  scrollListener = () => {
    clearTimeout(timeoutId);

    // Scroll completion criteria: either reaching the target position or 100ms elapsing since last scroll event
    if (container.scrollTop === position) {
      finished();
    } else {
      timeoutId = setTimeout(finished, 100);
    }
  };

  container.addEventListener('scroll', scrollListener);

  container.scrollTo({
    top: position,
    behavior: 'smooth',
  });

  return promise;
}

Answer №4

I have implemented a function that scrolls an element to a specific position using a similar approach:

function scrollToPosition(element, position) {
  return new Promise((resolve) => {
    const scrollHandler = (event) => {
      if (typeof event === 'undefined') {
        return;
      }

      const targetElement = event.currentTarget;

      if (targetElement.scrollTop === position) {
        targetElement.removeEventListener('scroll', scrollHandler);
        resolve();
      }
    };

    element.addEventListener('scroll', scrollHandler);

    // Scroll to the desired position
    element.scrollTo(0, position);
  });
}

const container = document.querySelector('#theScrollContainer');
const desiredYPosition = 300;

scrollToPosition(container, desiredYPosition).then(() => {
    // Perform additional actions once scrolling is complete
});

Answer №5

When considering various scenarios, it is important to:

  • be mindful of users trying to interact with a web browser while scrolling
  • take into account situations where the web browser has a set zoom level and floating-point numbers are returned by the DOM API.

Source:

function SmoothScroller(element, interval = 100, chances = 3, tolerance = 1.0) {
    let id = null;
    this.scroll = (x, y, callback) => {
        if (id) {
            clearTimeout(id);
            id = null;
        }
        const options = {
            left: x,
            top: y,
            behavior: 'smooth'
        };
        element.scrollTo(options);
        if (callback) {
            let state = +Infinity;
            const action = () => {
                const elementX = element.scrollLeft;
                const elementY = element.scrollTop;
                const dx = x - elementX;
                const dy = y - elementY;
                const square = dx * dx + dy * dy;
                if (square < tolerance) {
                    callback('done');
                } else {
                    const dx = x - elementX;
                    const dy = y - elementY;
                    const space = dx * dx + dy * dy;
                    if (square === state) {
                        if (chances > 0) {
                            state = space;
                            chances -= 1;
                            id = setTimeout(action, interval);
                        } else {
                            callback('canceled');
                        }
                    } else {
                        state = space;
                        id = setTimeout(action, interval);
                    }
                }
            };
            id = setTimeout(action, interval);
        }
    };
    this.stop = () => {
        if (id) {
            clearTimeout(id);
            id = null;
        }
    };
}


// Usage example:

const element = ...  // e.g. document.querySelector('#element');
const scroller = new SmoothScroller(element);

scroller.scroll(50, 100, (status) => console.log(`status: ${status}`));  // scrolls into (x, y) = (50, 100) position

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Trouble getting Fontawesome icons to accept color props when using react functional components with tailwindcss

Issue I'm Facing I'm currently working on a project that involves using icons extensively. Instead of manually adding a Fontawesome icon in every script, I have created a functional component that handles the rendering of icons based on given pr ...

Using PHP to Generate Validation Rules for jQuery

I have been exploring the jQuery Validation plugin and came across the use of a callback to send additional data, such as a username, as mentioned in the official documentation. var myObj={ rules: { email: { required: true, ...

showing input using an array

I need some assistance with my JavaScript code. I have created three input boxes where users can add data, and then click a button to add the data into an array. The goal is to allow multiple users to input data and then display all values in the array alo ...

What is the scope of values in Javascript/jQuery?

Similar Query: Does JavaScript have a range() equivalent? Can we define a range in JavaScript or jQuery similar to how it's done in Python? For example: x = range(1,10) x = [1,2,3,4,5,6,7,8,9] Appreciate your inputs. ...

Incorporating an HTML header into a QNetworkReply

I have implemented a customized QNetworkAccessManager and subclassed QNetworkReply to handle unique AJAX requests from a JavaScript application. It is functioning mostly as expected, but I have encountered an issue where my network replies seem to be missi ...

Develop a JavaScript function to generate a multiple selection form

Hey there! I have a question... Can I use JavaScript to create a multiple select form? Here's an example: <select name="item[]"> <option value="0">Option 1</option> <option value="1">Option 2</option> </select> &l ...

What is causing the lack of category options to appear in the select menu?

I've been trying to populate a select menu with categories from the database using this code, but it doesn't seem to be working as expected. <select onChange={handleChange("category")} className="form-control&quo ...

Ways to conceal <td>s in angularjs on specific rows during ng-repeat

In the first <tr>, I have a table with many <td> elements that I am populating using ng-repeat. <tr ng-repeat="receipt in $data"> <td data-title="voucher number"> <span>{{receipt.voucher_no}}</span> </td ...

An issue has been detected in the constants.json file located in the constants-browserify

I organized my folders into client-side and server-side categories, but I failed to work from a parent folder perspective. Now, as I attempt to deploy to Heroku, I realize that I need one main folder for the deployment process. To address this issue, I dec ...

What is the best way to implement ES2023 functionalities in TypeScript?

I'm facing an issue while trying to utilize the ES2023 toReversed() method in TypeScript within my Next.js project. When building, I encounter the following error: Type error: Property 'toReversed' does not exist on type 'Job[]'. ...

Angular directive used to create a nested tree list

Currently struggling with a nested list Directive in Angular. Whenever I attempt to run the code, the browser crashes due to the recursive call of the directive. My goal is to display a new list item if the data's children property contains items. H ...

Transform Circle into Square using C3.js

I am currently exploring c3.js and I am curious if there is a method to modify the circles present in a scatter plot to a different shape, such as a rectangle. Perhaps utilizing a d3 script? I am aiming to utilize different shapes to distinguish between t ...

For every iteration, verify the presence of the image

I am currently working on a foreach loop to iterate over the data returned by an ajax call. Within this loop, I am checking if each record has an associated image. Code for Checking Image Existence: function checkImageExists(url, callback) { var img ...

Update the ng-repeat attribute in HTML using either vanilla JavaScript or AngularJS

When the user clicks on the 'sort by book title' button, I want to change the ng-repeat="x in books' to ng-repeat="x in books|orderBy:'country'" in the HTML code. How can I achieve this action using JavaScript/Angular? Here is a ...

Utilizing PHP Variables in an External JavaScript: A Step-by-Step Guide

I am attempting to utilize an array generated in PHP within my external JavaScript. My PHP code retrieves images from a directory based on the user ID provided via URL and stores them in an array. I aim to use this array in JavaScript to create a photo sli ...

How to utilize local functions within a ko.computed expression

Why isn't this line of code working? I'm using durandal/knockout and my structure is like this define(function () { var vm = function() { compute: ko.computed(function() { return _compute(1); // encountering errors }); ...

What is the best way to stop div animations when clicking with jQuery?

Upon loading the page, a div animates automatically. There is also a button present. When the button is clicked, I would like to create a new div and animate it the same way as the first one. However, when this happens, the position of the first div also ...

A guide on triggering a new chart to appear beside the adjacent <div> when a bar is clicked in a highchart

I'm a beginner with Highcharts and I have a requirement for two charts (let's call them Chart A and Chart B). Creating one chart is straightforward. What I need is, upon clicking on a bar in Chart A, a new chart (Chart B) should open next to the ...

Ways to transform epoch timestamp to present timestamp?

Is there a way to accurately convert an epoch timestamp in milliseconds to the current timestamp in milliseconds? My Attempt: var currentTime = (resp.timestamp * 1000) + 1980000000; resp.timestamp represents the epoch timestamp I attempted to add 5 ho ...

Obtaining connection data in jsPlumb can be accomplished through a variety of

I have created a compact table of nodes that allow me to drag and drop connections or manually input node IDs to establish connections between them. Despite searching through the documentation and scouring the internet for examples, I am struggling to fin ...