VueJS Components using scrollIntoView()

benedemon picture benedemon · Jun 17, 2017 · Viewed 15.4k times · Source

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?

Answer

Bert picture Bert · Jun 17, 2017

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.