[solved] When is Dom ready for scroll?



  • I have multiple children and need to scroll to a certain child after loading the page. I can do so by setting a delay using setTimeout but I would prefer a better/ fail-proof solution. My current approach is to wait for all children to mount (and use nextTick) and thought it should be ready for the scroll, but apparently not. Alternatively I can wait for all images to be loaded (as QImg has a @load event), but that is really late, since manually I can already trigger a scroll while image boxes are already rendered but still loading. What is the best way to trigger at ‘the earliest possible moment’?

    Point-panel (parent):

    new Vue({
      el: '#q-app',
      template: `
          <div id="point-panel" class='map-overlay column scroll'>
                <small-cards @child-mounted='cardsAreReady' 
                     v-for='(point, cardIndex) in picArray'
                     :key="cardIndex"
                     :point-object="point"
                     :card-index="cardIndex"></small-cards>
                <q-btn @click.native="scrollToCenter"
               fab
               ripple
               class='fixed'
               size="10px"
               color="black"
               label="scroll"
               style="right: 18px; bottom: 120px" />
      </div>
            </div>
        `,
      data() {
        return {
          parentMounted: false,
          selectedPointIndex: 6,      
          picArray: ["https://image1", "https://image2, "https://image_etc."]
         }
          },
          mounted: function() {
          let that = this
          	that.$nextTick( function(){
            	that.parentMounted = true
            })
          },
          methods: {
            notify(msg) {
              this.$q.notify(msg)
            },
            cardsAreReady(cardIndex) {
              console.log('one ready.......', `${cardIndex + 1} ...and total ${this.picArray.length}`)
              let that = this
              if (cardIndex + 1 === this.picArray.length) {
                console.log('....all cards MOUNTED!', cardIndex)
                setTimeout(() => {
                  that.$nextTick(() => {
                    console.log('..........trigger scroll NOW!')
                    if (that.parentMounted === true) {
                      that.scrollToCenter()
                    } else {
                      that.$q.notify('parent not yet ready!!')
                    }
                  })
                }, 0)
              }
            },
            scrollToCenter() {
              const that = this
              console.log('..........cardIndex: ', that.selectedPointIndex)
        
        
              function scrollFunction() {
                that.notify('scroll triggered!')
                const element = document.getElementsByClassName(
                  that.selectedPointIndex.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)
        
              }
              setTimeout(() => scrollFunction(), 0)
            }
          }
        })
        
    

    Images/ small-cards (children):

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

    Here you can find a jsfiddle showing the issue. I have added a scroll button to show that after loading you can trigger a scroll successfully (the 6th picture, i.e. ‘the Tiger’ is scrolled to the bottom-left corner).

    To give the question somewhat more direction: The problem is that if scroll is triggered to soon the Dom is not yet rendered and thus the distance to scrol can not yet be determined. But I would think that after mount in combination with $nextTick the Dom should be determined?! So why does current approach not work?



  • After using @load for the scroll-element and adding a nextTick it seems to work as should. See this stackoverflow-issue .


Log in to reply