Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

offset always returns zero within a modal #986

Closed
musicformellons opened this issue Oct 11, 2017 · 11 comments
Closed

offset always returns zero within a modal #986

musicformellons opened this issue Oct 11, 2017 · 11 comments

Comments

@musicformellons
Copy link
Contributor

I have a modal with cards in it, which works fine. I would like the modal to have scrolled to a specific (not at the top) card when opening the modal, but I run into problems.

I am trying to use getScrollTarget and setScrollPosition following the docs. E.g. I can do:
setScrollPosition(getScrollTarget(element[0]), 500, 1200)
Which works nicely and shows an animated scroll of 500 px. To scroll to the correct card I need to set the correct distance of px so I would like to use:
offset(element[0])

But this always returns 0. Also getScrollbarWidth gives 0.

When I use these methods in a non modal window with cards I do get sensible values. So, is there a reason why offset does not work within the modal?

My component:

<template>
    <q-modal ref="myModal" maximized class="scroll overflow-hidden">
      <q-modal-layout>
        <div class="layout-padding">
          <q-card inline
                  center
                  v-for="task in tasks"
                  :class="task.getAttribute('id')"
                  :key="tasks.id"
          >
            <q-card-media>
              <img :src="task.getAttribute('image')">
            </q-card-media>
            <q-card-main>
              <div>{{ task.getAttribute('myname') }}</div>
            </q-card-main>
          </q-card>
        </div>
      </q-modal-layout>
    </q-modal>
</template>

<script>
import {
  scroll,
  dom
} from 'quasar'
const {getScrollTarget, setScrollPosition, getScrollbarWidth} = scroll
const {offset} = dom

export default {
  name: 'myModal',
  components: {
    scroll,
    dom
  },
  methods: {
    open (clickID) {
      this.$refs.myModal.open()
      const element = document.getElementsByClassName(clickID.toString())
      console.log('element', element)
      setScrollPosition(getScrollTarget(element[0]), 500, 1200)
      console.log('offset(element[0])', offset(element[0]))
      console.log('getScrollbarWidth()', getScrollbarWidth())
    }
  }
}
</script>
@musicformellons
Copy link
Contributor Author

Just now I found this which might be relevant here as well. I will dig into it.

@musicformellons
Copy link
Contributor Author

Yeah, triggering offset with the @open event solved it.

@musicformellons
Copy link
Contributor Author

musicformellons commented Oct 12, 2017

Uh, do you maybe have a suggestion which event to use exactly? At the open event the css apparently is not loaded since when the list of cards gets larger I see the offset losing accuracy, so it is called 'too early'. When I use setTimeout(myFunction, 200) I get good results, I would prefer using an accurate event though.

I tried:

  • using document.load
  • using vue mount

Both do not work. It seems maybe because the modal is already mounted, so it is not triggered when it opens...

Any help maybe?

@igorgo
Copy link

igorgo commented Oct 17, 2017

I could be wrong, bat maybe it's all because of the asynchronous animation. Try to play with the last argument of setScrollPosition down to 0.

@musicformellons
Copy link
Contributor Author

musicformellons commented Oct 17, 2017

I already did, but keeps same problem.

@igorgo
Copy link

igorgo commented Oct 17, 2017

I had solved the similar problem (scroll specific card to ScrollArea's center ) as follows.

scrollToRecord ({pos}) {
        const target = scroll.getScrollTarget(this.$refs['list'].$el)
        if (target) {
          const activeCard = this.$refs['list'].children[pos]
          let offset = activeCard ? activeCard.offsetTop : 0
          offset -= Math.floor(this.$refs['scroll'].$el.clientHeight / 2)
          offset += Math.floor(activeCard.clientHeight / 2)
          scroll.setScrollPosition(target, offset)
        }
      }

@musicformellons
Copy link
Contributor Author

musicformellons commented Oct 18, 2017

@igorgo Thanks! My problem is not determining the accurate scrolldistance for the card. Using setScrollPosition(getScrollTarget(element[0]), myOffset, 0) works when I call it with setTimeout with a delay of 200ms (but this could still fail on a slower machine etc.). So I need to find the right hook which will give me when the dom is ready rendering the modal content. I could hack around it by running the getScrollTarget repeatedly till it gives a consistent value for e.g. three times or so, this is ugly though. Was hoping Razvan could maybe shed some light on this.

@rstoenescu
Copy link
Member

Hi,

  1. Lose class="scroll overflow-hidden" on the q-modal
  2. The scroll happens on a div with "q-modal-layout-content col scroll" class.
  3. You need to listen to @open event and then scroll to the desired position. Use getScrollTarget(ref_to_element_inside_layout_padding_including) then setScrollPosition

@musicformellons
Copy link
Contributor Author

@rstoenescu Just to be clear: my code 'works': the scroll does happen. My problem is the correct triggermoment. I have to set a delay otherwise the dom is not ready or something.

I did alter my code after your comment:

<template>
  <q-modal ref="myModal"
           maximized
           @open="myScroll()">
    <div class='q-modal-layout-content col scroll'>
    <q-modal-layout>
        <div class="layout-padding">
          <q-card inline
                  center
                  v-for="task in tasks"
                  :class="task.getAttribute('id')"
                  :key="tasks.id"
          >
            <q-card-media>
              <img :src="task.getAttribute('image')">
            </q-card-media>
          </q-card>
        </div>
    </q-modal-layout>
    </div>
  </q-modal>
</template>

<script>
import {
  scroll,
  dom
} from 'quasar'

const {getScrollTarget, setScrollPosition} = scroll
const {offset} = dom

export default {
  name: 'myModal',
  components: {
    scroll,
    dom
  },
  methods: {
    open (clickID) {
      this.$refs.myModal.open()
      this.clickID = clickID.toString()
    },
    myScroll () {
      const myFunction = () => {
        const element = document.getElementsByClassName(this.clickID)
        let myOffset = ((offset(element[0]).top) - 13)
        setScrollPosition(getScrollTarget(element[0]), myOffset, 0)
      }
      setTimeout(myFunction, 200)
    }
  }
}
</script>

But my issue remains the same. When I set setTimeout(myFunction, 0) the myOffset is not accurate.

@rstoenescu
Copy link
Member

offset import tells the offset of element on screen, it does not tell the scroll position of the element within an overflowed DIV. Just find some other way to tell this position.

@musicformellons
Copy link
Contributor Author

@rstoenescu Pheew! That's it! Thanks a bunch!!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants