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

Feature request: replace routes dynamically #1234

Open
alekbarszczewski opened this Issue Mar 9, 2017 · 18 comments

Comments

Projects
None yet
@alekbarszczewski

alekbarszczewski commented Mar 9, 2017

Right now it is possible to dynamically add routes by calling router.addRoutes([/* routes */]). It would be nice if it was possible to also remove/replace routes on the fly. In my app user may define routes by himself (on the fly). I keep user configuration in the Vuex store, and when it is updated I want to completely replace whole router routes configuration (though replacing/removing single route would be also handful but I guess then it should also handle removing/replacing/adding child routes instead of only dealing with top-level routes, which would be quite complicated). I imagine that after replacing routes router would check if current path matches any of the new routes and navigated to it.

It could be for example method router.replaceRoutes([/* routes */]) or router.setRoutes (in addition to method router.addRoutes which already exists).

Please note that this situation can be handled without VueRouter by setting one global route /* that will match every possible path, performing route matching inside this global route component (based on dynamic config stored in Vuex store for example) and dynamic rendering of component(s) that matched current path. However this is very ugly solution which looses all benefits of VueRouter, and handling child routes would be complicated.

In fact I wanted to handle it by patching VueRouter manually, but it seems that createMatcher (https://github.com/vuejs/vue-router/blob/dev/src/create-matcher.js#L16) does not expose pathMap and nameMap so it is not possible modify routes configuration in other way than by calling router.addRoutes (I guess it's intentional :).

@posva

This comment has been minimized.

Member

posva commented Mar 9, 2017

Why would you ever need to delete a created route without adding a new one replacing it?
I think you may be interested in #1129

@alekbarszczewski

This comment has been minimized.

alekbarszczewski commented Mar 9, 2017

In my app user may dynamically set routing. For example he has three predefined components A, B and C; In the application (in browser :) he can manage route configuration; let's say there is a textarea with following JSON:

[{ path: "/my-custom-path", component: "A" }, { path: "/some/other/path/:id", component: "B" }, ...]

For now I can just add new routes to the router:

import A from '@/components/A';
import B from '@/components/B';
import C from '@/components/C';

const allComponents = { A, B, C }; 

// "routes" is array of routes provided by user/client in textarea (textarea is just an example :).
onConfigChanged = routes => {
  routes = routes.map(route => {
    return { path: route.path, component: allComponents[route.component] };
  });
  router.addRoutes(routes);
};

// onConfigChanged is called on each change to configuration by user/client

What I need is to completely replace all routes: router.replaceRoutes(routes) or maybe router.addRoutes(routes, { replace: true }) (it should completely replace routes configuration).

#1129 is close but it won't solve my problem because I don't know route names...

I know that this is not primary use-case for VueRouter, but it would allow to do more advanced things (like my use-case).

@ianaya89

This comment has been minimized.

ianaya89 commented Mar 17, 2017

I like this feature request, I have uses cases where I need to replace url parameters dynamically just to generate a URL to share and grant a unique access for a view with data that I already have in memory (where I don't need view changes or async operations).

@nickforddesign

This comment has been minimized.

nickforddesign commented Apr 12, 2017

My application has different very routes for different user roles (some are replaced, some should be inaccessible or not exist at all). While it is already possible to achieve this using hooks and basic permissions definitions, I am interested in the idea of replacing the routes entirely on login/logout. The set of routes available could then be unique for each user role, and public/non-authenticated users.

@fritx

This comment has been minimized.

fritx commented Jul 1, 2017

I had my components depends on the api, and the api now needs to depend on the router,
however, the router has to depend on the components,
because of the new Router({ routes: [{ component }] }) syntax,
which causes a circular require now.

(the resolve => reuqire([path], resolve) syntax doesn't work for me.)

+1 for dynamic routes config, so I can export the router instance first.

alekbarszczewski added a commit to alekbarszczewski/vue-router that referenced this issue Jul 14, 2017

feat(router): add 'replaceRoutes' method
'replaceRoutes' method replaces all routes in router

close vuejs#1234

@alekbarszczewski alekbarszczewski referenced a pull request that will close this issue Jul 14, 2017

Open

feat(router): add 'replaceRoutes' method #1603

@vuejs vuejs deleted a comment from lerit Sep 18, 2017

@vuejs vuejs deleted a comment from Telanx Sep 18, 2017

@vuejs vuejs deleted a comment from fancyboynet Sep 18, 2017

@nickforddesign

This comment has been minimized.

nickforddesign commented Sep 26, 2017

Is there any intention of implementing this? It felt like there was some momentum on this for a while

@posva posva removed the 2.x label Oct 8, 2017

@frenchbread

This comment has been minimized.

frenchbread commented Dec 1, 2017

My use case: Modular app, where you enable/disable modules (basically separate components, pages) that have pre-configured routes. Adding a route after enabling a module is ok, but when disabling module, previous routes need to be removed.

@goldenram

This comment has been minimized.

goldenram commented Dec 7, 2017

I agree this is needed. Imagine you implement a landing page that loads various apps dynamically, so that each app loaded would want to clear any previously loaded routes and load its own in. Also imagine that this information is sent up from the server dynamically.

This seems like a simple api of router.removeRoutes ([routeKeys]) or empty array to remove all.

@vuejs vuejs deleted a comment from frenchbread Dec 7, 2017

@khaledh

This comment has been minimized.

khaledh commented Dec 28, 2017

The case for authorization-based (or capability-based) route definitions seems to be very common for sufficiently sophisticated apps.

In my case (somewhat similar to @nickforddesign's), I'd love to be able to start with a minimal set of public routes for unauthenticated users, and if they try to access any of the protected routes they get a 404 (or maybe redirected to login). Upon login, the server would respond with a list of accessible routes based on the current user role and/or app configuration.

@JounQin

This comment has been minimized.

Contributor

JounQin commented Dec 29, 2017

All interceptors and authentications can be implemented with beforeEach hook, I still don't understand why you need add or replace routes dynamic.

@silkentrance

This comment has been minimized.

silkentrance commented Dec 29, 2017

@JounQin Please consider a client side plugin system that allows individual plugins to be disabled/enabled. When enabled, the routes provided by the plugin must be added to the system. When disabled, these routes need to be removed again in order for the application to fail consistently, namely with a 404 instead of continuing to render the components/views associated with that route.

An alternative, of course, would be to implement a beforeEnter hook which checks whether the route is available and redirecting to 404 instead when it is not.

@limoli

This comment has been minimized.

limoli commented Jan 3, 2018

@posva

Why would you ever need to delete a created route without adding a new one replacing it?
I think you may be interested in #1129

How could you implement this? Is it possible to create a new Router and assign it to the main app Router?

@coxy

This comment has been minimized.

coxy commented Jan 16, 2018

@limoli I had the same issue and solved it by replacing the router's matcher object with one from a newly created router instance.. something like:

import Vue from 'vue'
import Router from 'vue-router'

Vue.use(Router)

const createRouter = () => new Router({
  mode: 'history',
  routes: []
})

const router = createRouter()

export function resetRouter () {
  const newRouter = createRouter()
  router.matcher = newRouter.matcher // the relevant part
}

export default router
@xon52

This comment has been minimized.

xon52 commented Jan 24, 2018

I'm really keen on having this feature. My app dynamically loads/unloads content, so if I unload a module, it'd be fantastic if it's be easy to unlink the routes (and redirect to my 404 or home page).
Edit: Router guards can work, but this would be much easier because I wouldn't need to have like 20 guards in place to accommodate all my separate modules... Oh, and I don't think we can dynamically add router guards?

@JesseZhao1990

This comment has been minimized.

JesseZhao1990 commented Mar 15, 2018

@coxy great~ it works~

@ale-grosselle

This comment has been minimized.

ale-grosselle commented May 4, 2018

I have similar problem: I have many minis app with its routes: Content app, User app.
A main app, used and load these mini apps.
Main app load mini app asynchronously.

My goal is:

  1. User wants to go "content/details/video_1"
  2. Main app seeing the hash, knows that users wants to use mini app "Content". So, mini app "Content" and its routes are loaded?
  3. If no, ok loaded component, apply routes and finally show the component

Below my code:
MAIN APP Router code:

import Vue from "vue";
import Router from "vue-router";
import HelloWorld from "@/components/HelloWorld";

Vue.use(Router);

const loadSection = function(to, next) {
	//Load Content section:
	if (to.includes("/content")) {
		let promiseContent = import("dynamicImports/Content");
		promiseContent.then(
			(contentItem) => {
				contentItem = contentItem.default;
				//call init mini app (add routes mini app):
				contentItem.init(router);
				//After apply mini app routes, i must to force next(to)
                                //instead of next(). next() do nothing... bug???
                                 next(to);
			}
		);
	} else {
		next();
	}
};


const router = new Router({
	routes: [
		{
			path: "/",
			name: "HelloWorld",
			component: HelloWorld
		}
	]
});

router.beforeEach((to, from, next) => {
	if (router.match(to.path).matched.length === 0) {
		loadSection(to.path, next);
	} else {
		next();
	}
});

export default router;

MINI APPS EXPORT (dynamicImports/Content):

import RouterConfig from "router";
import MainApp from "components/app.vue";
import ContentDet from "components/contentDetails/ContentDetails.vue";

export const App = {
	component: MainApp,
	init: function(router:any) {
		//Add routes:
		router.addRoutes(RouterConfig);
	}
};

what do you think of this solution?

@johnny-dash

This comment has been minimized.

johnny-dash commented Aug 3, 2018

Similar problem to me as the complex system has many different roles and authorizations. Instead of adding security check to each root components and do conditional rendering, it is better to have access control in the router level. In addition, it makes no sense to let the user access the route if they can see nothing there.

Thanks for @coxy 's patch, but we still need the official methodology to address this problem as this patch might not work after library upgrade. (And the complain from Tslint)

Please, Please, Please

Ps: it's interesting that Vue-router ONLY have addRoute method there, it makes me feel like I can only add money to wallet while I never get a chance to spend them ;)

@wangqiang66

This comment was marked as spam.

wangqiang66 commented Oct 18, 2018

为什么不将createMatcher方法放开,这样这个router里面的matcher不是可以自己生成,动态修改起来也方便,动态修改routeList不是也很方便

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment