Determining the optimal timing to initiate a scroll once images have finished loading

When using the Quasar framework, I encountered a challenge with scrolling to a specific child element after the page has loaded. Currently, I achieve this by implementing a delay using setTimeout, but I am seeking a more reliable solution.

My current approach involves waiting for all children to mount (using nextTick) and assuming that it would be ready for scrolling, however, this is not the case. Another option could be waiting for all images to load (as QImg has an @load event), but this occurs too late since manual scrolling can already take place while the image boxes are being rendered and loaded.

Is there a better way to trigger the scroll at the 'earliest possible moment'?

In the parent component Point-panel:

// Vue instance code goes here

In the child components Images/small-cards:

// Vue small-cards component code goes here

You can view the issue demonstrated in this JSFiddle. A scroll button has been added to showcase successful scrolling after loading (the 6th picture, the 'Tiger', scrolls to the bottom-left corner).

EDIT: To provide some direction to the question - the problem arises when the scroll is triggered too early before the DOM is fully rendered, therefore the distance to scroll cannot be determined. After the mount phase, I expect the DOM to be complete. Why does the current approach fail in achieving this goal?

Answer №1

UPDATE/NEW ANSWER:

After several attempts, I finally managed to make it work. Here are the steps I took to resolve the issue:

  • ~UPDATE~ By incorporating $nextTick (suggested by the original poster), the consistency of the solution improved significantly! The original poster was also able to achieve success without using a wrapper component.
  • The small-cards component now emits an event after the image finishes loading.
  • Introduced a "wrapper" named small-cards-wrapper for the small-cards component.
  • This "wrapper" includes 2 props: 1) items, which is an array of image sources 2) scrollToIndex, representing the index number to scroll to upon mounting.
  • The small-cards-wrapper component listens for the emitted event (from small-cards component[s]) and checks if it matches the desired scroll index - if so, it initiates the scroll operation...
  • In essence, we wait for the image to load before attempting to scroll to it...

You should be able to identify the changes I made by examining the code. Feel free to reach out if you have any queries!

[LATEST JSFiddle (featuring $nextTick)]

[UPDATED JSFiddle]



ORIGINAL RESPONSE:

I executed the scrollToCenter() method during the mount phase, while removing the hook.mounted logic from the template...

I've annotated the aforementioned modifications within the code so that you can see the exact alterations made...

If you prefer not to have the scroll occur 2 seconds post-mount, you can eliminate the setTimeout - it was added to demonstrate the scrolling behavior post-loading (providing time to observe the transition)...

Does this align with your requirements?



Vue.component('small-cards', {
  props: {
    pointObject: {
      type: Object,
      required: true
    },
    cardIndex: {
      type: Number,
      required: true,
      default: 0
    },
  },
  data: function() {
    return {
      selectedPointIndex: 6
    }
  },
  methods: {
    reportError(event) {
      console.log(`${event.name}: ${event.message}`);
    },
    handleLoad() {
      this.$emit('loaded-card', true);
    }
  },
  template: `
  <div class="mycard" :class="{[cardIndex]: true}">
    <q-img :src="pointObject"
    @load="handleLoad"
      spinner-size="30px"
      style="background-color: rgba(255, 225, 215, 0.4)"
    @error="reportError">
    </q-img>
  </div>
  `
});

Vue.component('small-cards-wrapper', {
  props: {
    items: {
      type: Array,
      required: true,
    },
    scrollToIndex: {
      type: Number,
      required: false
    }
  },
  methods: {
    isLoaded(x) {
      if (Number(x) === Number(this.scrollToIndex)) {
        this.$nextTick(() => {
          const element = document.getElementsByClassName(x.toString())
          const target = document.getElementById('point-panel')
          const iW = window.innerWidth
          const iH = window.innerHeight
          const myOffset = element[0].offsetLeft
          Quasar.utils.scroll.setHorizontalScrollPosition(target, myOffset, 0)
          this.$q.notify("Scroll Triggered!");        
        })
      }
    }
  },
  template: `
<div id="point-panel" class='map-overlay column scroll'>   
  <small-cards
    v-for='(point, cardIndex) in items'
      :key="cardIndex"
      :point-object="point"
      :card-index="cardIndex"
      @loaded-card="isLoaded(cardIndex)"
    ></small-cards>
  </div>
  `

})

new Vue({
  el: '#q-app',
  data: function() {
    return {
      selectedPointIndex: 6,
      picArray: ["https://images.takeshape.io/86ce9525-f5f2-4e97-81ba-54e8ce933da7/dev/144069dc-7390-4022-aa0f-abba022d3a2f/spec.jpg?auto=compress%2Cformat", "https://natureconservancy-h.assetsadobe.com/is/image/content/dam/tnc/nature/en/photos/prescribed_burn_oregon.jpg?crop=0,120,5760,3600&wid=1640&hei... 

<link href="https://unpkg.com/<a href="/cdn-cgi/l/email-protection" class="__cf_email__" data-cfemail="d3a2a6b2a0b2a1feb6aba7a1b2a093e1fde3fdea">[email protected]</a>/material-icons/material-icons.css" rel="stylesheet"/>
<link href="https://cdn.jsdelivr.net/npm/quasar@^1.0.0-beta.0/dist/quasar.min.css" rel="stylesheet" type="text/css">

<script src="https://cdn.jsdelivr.net/npm/quasar@^1.0.0-beta.0/dist/quasar.umd.min.js"></script>

<div id="q-app"></div>

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

Html.BeginForm does not offer onBegin or onComplete methods similar to Ajax.BeginForm

I am currently working with ASP.NET MVC 5 and have implemented a loader during form submission using Ajax.BeginForm: @using (Ajax.BeginForm("Filter", "Log", new AjaxOptions() { OnSuccess = "reloadGrid", OnFailure = "notifyError", HttpMethod = "POST", Load ...

Steps for triggering a re-render in a React component when an external value changes

I am currently working on a project that involves using Meteor and React. In my code, I have a class called WebRTC which handles all WebRTC-related logic: class WebRTC { this.isCalling = false; ... } In addition to the WebRTC class, there is ...

Leveraging PrimeFaces and the p:ajax component, trigger Ajax within an inputText field only when keystrokes lead to changes in the field

I am currently utilizing PrimeFaces and have a p:inputText field that requires updating certain components on the view based on the most recent keystroke within that p:inputText. Below is the code snippet: <p:inputText value="#{customerLController.surn ...

Struggling with displaying MySQL data in JSON format using Highcharts

Currently, I am attempting to display data from a PHP file on an area graph by using the example found here. Initially, all the data was commented out before being passed to the array. Now, my focus is solely on displaying one portion of the data. I suspec ...

Tips on setting and utilizing custom environment variables in a Vue Electron application

What is the best way to integrate custom environment variables into my Electron application? I need to securely store API keys and other sensitive information without hardcoding them directly into the code. My app is built with Vue and Electron. To tackle ...

What is the most optimal jQuery code to use?

Just wondering, which of the following code snippets is more efficient (or if neither, what would be the best way to approach this)? Background - I am working on creating a small image carousel and the code in question pertains to the controls (previous, ...

Utilizing Jquery to extract a specific string from a URL and fetch a remote element

Recently delving into Jquery, I'm in search of a code snippet that can capture the current page URL and load a remote element if it contains a specific string. For instance: Consider these sample page URLs: "http://......./Country/AU/result-search- ...

Utilizing the random function in a loop can result in unpredictable and unexpected values

Why is it that I get numbers ranging from 17 to 70,000 in the three console.log statements? However, in the loop, y always seems to fall between 200 and 800. Why is that? console.log("RND " + Math.floor(Math.random()*5000)*17) console.log("RND " + Math ...

Utilizing axios and Vue to access the Twitch API

Currently, my goal is to integrate the Twitch API for user sign-ins, but I've encountered some challenges along the way. Below is the initial code snippet that I have developed: <template> <section> <form class="pt-6 pb-8 animat ...

How can I make it so that clicking on the links will display the data in the divs?

I am facing an issue with my code. Despite clicking on the links, the data is not showing up in the divs as expected. Can anyone provide some suggestions on why this might be happening? I suspect there may be an error in my script setup. <!DOCTYPE h ...

Issue with MongoDB find() function not retrieving any results (Assignment)

I am currently working on an assignment that requires the use of noSQL databases. Although I understand most of the queries we have to perform in mongoDb, every query I execute seems to return a blank result. Initially, we are required to create a collect ...

[Error]: Unable to access the 'getCroppedCanvas' property as it is undefined in React Cropper

I am currently utilizing the "React Cropper" library (https://www.npmjs.com/package/react-cropper). I have included this code snippet (similar to many examples): import React from 'react'; import Cropper from 'react-cropper'; export ...

Ways to convert an object with values into an array containing those values

To process the JSON data and convert it into an array with the same values for insertion into my PostgreSQL database using pool.query(message, values), where values should be an array if multiple are present. Currently, my object structure is as follows: { ...

How can I hide a root layout component in specific nested routes within the app directory of Next.js?

Is there a way to prevent rootlayout from being wrapped around dashboardlayout? Explore the latest documentation for Next.js version v13: https://i.sstatic.net/M0G1W.png Take a look at my file structure: https://i.sstatic.net/nVsUX.png I considered usi ...

Best practices for authenticating methods with Google signin in Angular projects

I have made significant progress towards getting the Google signin feature to work, reaching 95% completion. However, I am currently facing two issues with the code. Here is a simplified version of my current implementation: loginWithGoogle(): void { //t ...

Custom model positioning capabilities in Autodesk Forge are highly dynamic and versatile

I am looking to create a viewer forge that can be linked to BIM 360. I want to incorporate a new feature using THREE.js where an object can dynamically follow GPS coordinates for model positioning. I have successfully integrated it into the FORGE viewer, b ...

What could be causing the API link to not update properly when using Angular binding within the ngOnInit method?

Hi there, I'm currently working on binding some data using onclick events. I am able to confirm that the data binding is functioning properly as I have included interpolation in the HTML to display the updated value. However, my challenge lies in upd ...

Javascript - understanding variable scope

Hey there! I have some code that I need help with var idx = 0; var size = 0; do { response.push({ key: "data" + idx, ajaxOptions: function () { var data = this.getPref("groupsCN"); var items = data.split('; ...

Is there a jQuery function that can produce repeated output and append content with each successive click?

Attempting to implement a dynamic searchbar with various parameters has led me to explore using jQuery to load and clone the searchbar file in order to append it to the body dynamically. I have made several attempts to modify selectors without achieving t ...

Disable the default controls on the Open Layers Bing Map

I am currently working on an App that utilizes Geolocation with Open Layers to load a Bing Map Layer. My goal is to enable touch-based zooming and remove the default zoom buttons. Additionally, I would like to relocate the 'i' button to prevent a ...