27

I'm trying to use a Jump-To-Div kind of feature using document.getElementById().scrollIntoView() in a vue component.

The feature works fine if I call the function when I'm in the component. But if I try to call the function from the parent component using a ref, the element is not scrolled into view.

The parent component is a page and the children components are tabs in the page.

This is the child Vue Component in the parent component :-

<el-tab-pane label="Solution Details" name="Solution Details" v-loading="loading">
                <solution-details
                    :formData="response"
                    ref="solutionDetails"
                    @done="$emit('done')">
                </solution-details>
            </el-tab-pane>

So there is a SolutionDetails.Vue child component which has a ref="solutionDetails". I am calling this method in the parent component using the ref for the child component:

handleClick(command) {
            this.activeTab = 'Solution Details';
            this.$refs.solutionDetails.showCurrent(command);
        },

There is a showCurrent function in the child component which should get executed for a argument "command". This is that function in the child component.

methods: {
        showCurrent(index) {
            document.getElementById(index).scrollIntoView();
        },

As you can see, showCurrent should get the element in the page and should scroll into view. If SolutionDetails.vue is the active tab, then the corresponding element is being scrolled into view perfectly fine. But I'm executing the parent function from some other tab, then the this.activeTab = 'Solution Details'; is executing, ie. the active tab is changing to SolutionDetails.vue but the requested element is not scrolled into view.

What should I do to scroll to a element when some other tab is the activeTab?

4 Answers 4

27

Actually you have to reference the element in the component. Something like this for example:

this.$refs.[ref name here].$el.scrollIntoView({ behavior: 'smooth' });
Sign up to request clarification or add additional context in comments.

2 Comments

Note that if the ref is added to a regular HTML element (as opposed to a custom Vue element), you should not use the $el. For more details, see this answer: stackoverflow.com/a/58393099/2884291
This $el thing just saved my night.
25

The problem is that scrollIntoView is called before the tab is rendered on the page because renders are asynchronous. Essentially, when you call

this.activeTab = 'Solution Details';

Vue does not immediately render the page, it just queues a render. However immediately after that you tell Vue to look for the rendered element and scroll to it. It's not there yet.

I think my first stab at solving this would be to use $nextTick.

this.$nextTick(() => this.$refs.solutionDetails.showCurrent(command))

That should wait for the render that needs to happen to occur before you attempt to scroll into view.

2 Comments

I forgot about the asynchronous nature completely. I only recently started working with these. Thank you very much!
@tony19 Thanks for the answer! For me, nextTick() doesn't work, however setTimeout() does. Shouldn't they mean the same in this context?
3

1: Give the element you want a ref name. Inside the function on the parent element , it's better to try to console.log(this.$refs.[ref_name]) to check which part will have the effect. It is not always the parent element. Really depends on your CSS structure. When submit the form and get error message, then the view go to the part you want.

if(this.errorMessage) {
    this.$refs.[ref_name].scrollIntoView();
}

2: For Vue.JS Multi Steps Form It is normal to use step for process like signup. What we have now is the view will stay the same as the first step. For example, if step one form is quite long with scrolling then go to step two the view will stay at the bottom. What we can do here to keep the view on the top: Give the top element a ref name like ref="top". In all the steps submit functions, just add this to keep the next page on the top:

this.$refs.top.scrollIntoView();

1 Comment

Note that if ref is in a element with v-for, an array of elements will be returned.
1

My solution was to put this in the mounted hook:

setTimeout(() => {
      this.scrollTo();
    }, "100");

In methods:

scrollTo() {
      this.$refs.target.scrollIntoView();
    },

1/10th of a second is enough for the component to load and is imperceptible to my eye. It appears instant.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.