Vue-router: Allow router.replace without triggering scrollBehavior

Created on 22 Feb 2018  路  11Comments  路  Source: vuejs/vue-router

What problem does this feature solve?

Using router.replace to update query parameters. However this triggers scrollBehavior and scrolls to the top. As far as I know, there is no way to distinguish between a push and a replace event.

What does the proposed API look like?

Here are some options:

Could be a simple boolean passed to the scrollBehavior function

scrollBehavior (toRoute, fromRoute, savedPosition, isPush) {

It could be put in the route object to be consistent with this suggestion: https://github.com/vuejs/vue-router/issues/1620

scrollBehavior (toRoute, fromRoute, savedPosition) {
    const isPush = toRoute.navigationType === 'push';

I could also work with the replace function accepting an additional parameter, or having a new signature, that simply updates the url and router.$route without going through guards, scrollbehavior etc. I originally just updated the state manually to circumvent this (using history.replaceState), however that caused some other sneaky bugs since vue-router didn't know about these changes.

router.replace(route, true)
// OR
router.replace(route, { noEvents/silent: true })
// OR
router.silentReplace(route)

Most helpful comment

If anyone has similar problems and finds this issue, I solved it by not scrolling if the only thing that changed was the query/hash:

scrollBehavior (to, frm, savedPosition) {
        if (frm && to.name === frm.name && _.isEqual(to.params, frm.params)) {
            return;
        }
               // Handle scroll
}

isEqual is a lodash function that makes a deep comparison of the two objects

All 11 comments

I'd rather keep it in #1620
To skip guards, I prefer using meta fields, they're there for that kind of stuff
I already have some helpers in mind and docs we should provide to help advanced use cases to combine them

hm, can i just add meta to the route and read from that?

yep, but it will be linked to the route, not the navigation. I don't see why you would need to skip navigation guards in a navigation, it could make things fail easily 馃

Hm, it appears i have to define meta for every route... this feature spans multiple routes. This is what I'm attempting:

router.setQuery = function (query) {
    const route = {
        name: app.$route.name,
        params: app.$route.params,
        query,
        meta: {
            isQueryUpdate: true,
        },
    };
    router.replace(route);
};

Any ideas?

I only use the query parameters for saving data that you might want when you share a link or reload the page. For example where you are in a list

You can add the meta in the route definition as well so it is always applied, but yeah, you have to define where to use it 馃檪

Yeah but I can't have it always apply, what I need is to be able to see the difference between a query parameter update and a navigation (push) to the page. It appears meta is only per route, and never per route object (ie per entry in router.routes, not per router.route object)

that's beforeRouteUpdate
Let's stop the discussion here, it's turning into a forum thread 馃槃

It's not the same because going from /product/1 to /product/2 through a push will still go through beforeRouteUpdate, while I want to prevent some behaviour when going from /product/1 to /product/1?image=2
Anyway thanks for the help. I'll add a +1 to the other issue and just fork in the meantime.

If anyone has similar problems and finds this issue, I solved it by not scrolling if the only thing that changed was the query/hash:

scrollBehavior (to, frm, savedPosition) {
        if (frm && to.name === frm.name && _.isEqual(to.params, frm.params)) {
            return;
        }
               // Handle scroll
}

isEqual is a lodash function that makes a deep comparison of the two objects

Similar, but without requiring lodash:

scrollBehavior (to, from) {
    // Skip if destination full path has query parameters and differs in no other way from previous
    if (from && Object.keys(to.query).length) {
        if (to.fullPath.split('?')[0] == from.fullPath.split('?')[0]) return;
    }
    // Handle scroll
}
Was this page helpful?
0 / 5 - 0 ratings

Related issues

posva picture posva  路  3Comments

kerlor picture kerlor  路  3Comments

mitar picture mitar  路  3Comments

marcvdm picture marcvdm  路  3Comments

shinygang picture shinygang  路  3Comments