Dynamic build routes {or dynamic component import} Angular 2 [duplicate] - dynamic

This question already has answers here:
Async load routes data and build route instruction for Angular 2
(4 answers)
Closed 6 years ago.
Maybe anyone know how to dynamicly build routes (or just dynamic import Components).
For example:
I have JSON that contains objects with RouteName, path, ComponentNames (string).
I want to iterate it and build dynamicly routes definitions (route config). But I don`t know, how to make dynamic Component import.
I can passs string "ComponentName" from JSON to import rule, because import want static definition (finded it on some soure from googling).
failed
let a = "MyComponentName"
import {a} from ......
(One idea that I came up with - its like create some map key-value, and keep into key - route, value - Component, and after that equals routename from JSON and my MAP and push needed component into final route config array. But its so ugly solution) Maybe another way exists?
I stuck. Many thanks for any help.....

You could leverage Async routes to do this. Based on your route configuration, you could load route from modules. In this case, you need to add the module path to get the components to associate with routes.
Here is a sample:
var routes = {
path: '/path',
name: 'some name',
module: './my.component',
component: 'MyComponentName'
}
routes.forEach((route : any) => {
this.routeConfigArray.push(
new AsyncRoute({
path : route.path,
loader : () => System.import(route.module).then(m => m[route.component]),
name : route.name
});
);
});
this._router.config(this.routeConfigArray);
Another approach could be to add a function to get the name of functions. Based on this you can check if you have a potential component that matches.
Here is a sample:
ngOnInit() {
this.routes = [
{
path: '/test', component: 'OtherComponent', name: 'Test'
}
];
this.configureRoutes(this.routes);
this.router.config( this.routes);
}
configureRoutes(routes) {
var potentialComponents = [ OtherComponent ];
routes.forEach((route) => {
route.component = potentialComponents.find((component) => {
return component.name === route.component;
});
});
}
See this plunkr: https://plnkr.co/edit/KKVagp?p=preview.
See this question for more details:
Dynamic Route Loading in Angular 2 Fails. (Beta)

https://github.com/angular/angular/issues/11437#issuecomment-245995186 provides an RC.6 Plunker
update
In the new router (>= RC.3) https://angular.io/docs/js/latest/api/router/index/Router-class.html#!#resetConfig-anchor resetConfig can be used
router.resetConfig([
{ path: 'team/:id', component: TeamCmp, children: [
{ path: 'simple', component: SimpleCmp },
{ path: 'user/:name', component: UserCmp }
] }
]);
original
What should work is
import from 'myComponents' as myComponents;
...
someFunc(name:string) {
console.debug(myComponents[name]);
}
Routes can be loaded using
constructor(private router:Router) { }
someFunc() {
this.router.config([
{ 'path': '/', 'component': IndexComp },
{ 'path': '/user/:id', 'component': UserComp },
]);
}
I haven't tried this myself.
See also this related question Angular2 App Routing through Services

say. three screens as page1, page2 and page3 and components as app/page1.ts, app/page2.ts and app/page3.ts
let screens : Array<string> = ["Page1","Page2","Page3"];
let aRouter : RouteDefinition;
this.routes = new Array<RouteDefinition>();
screens.map(function(screenId){
aRouter = new AsyncRoute({
path: "/" + screenId,
name: screenId,
loader: () => System.import("app/" + screenId).then(c => c[screenId]) // not import {page1, page2, page3}}
});
this.routes.push(aRouter);
}.bind(this)); //we need to bind to current "this" instead of global this
this.router.config(this.routes);
trick is .bind(this), which is vanella javscript
for whole sulution, check this
Dynamically load Angular 2 Async router
https://github.com/Longfld/DynamicalAsyncRouter

Related

Loading different components based on route param in Vue Router

I'm building an editor app which supports multiple design templates. Each design template has wildly different set of fields so they each has their own .vue file.
I'm trying to dynamically load the corresponding view component file based on params. So visiting /editor/yellow-on-black would load views/designs/yellow-on-black.vue etc.
I've been trying to do it like this
{
path: '/editor/:design',
component: () => {
return import(`../views/designs/${route.params.design}`)
}
}
But of course route is not defined. Any idea on how to work around this?
The route's component option is only evaluated once, so that won't work. Here's a solution using a Dynamic.vue view which uses a dynamic component based on the route param.
Use a simple route definition with route param. I changed the param name to dynamic:
import Dynamic from '#/views/Dynamic.vue';
{
path: "/editor/:dynamic",
component: Dynamic
}
Create a generic Dynamic.vue component that dynamically loads a component from the route param. It expects the param to be called dynamic:
<template>
<component v-if="c" :is="c" :key="c.__file"></component>
</template>
<script>
export default {
data: () => ({
c: null
}),
methods: {
updateComponent(param) {
// The dynamic import
import(`#/components/${param}.vue`).then(module => {
this.c = module.default;
})
}
},
beforeRouteEnter(to, from, next) {
// When first entering the route
next(vm => vm.updateComponent(to.params.dynamic));
},
beforeRouteUpdate(to, from, next) {
// When changing from one dynamic route to another
this.updateComponent(to.params.dynamic);
next();
}
}
</script>

Use same page for multiple routes

I am trying to find out how to use the same page for multiple routes on a Nuxt.js with i18n module.
Basically I want this route: /product-category/:slug/in/:material to use the same page as /product-category/:slug
So far I have tried below, adding it to nuxt.config.js - but it doesn't work. It simply shows the _slug/_material/index.vue file.
router: {
extendRoutes (routes, resolve) {
routes.push({
path: '/product-category/:slug/in/:material',
component: resolve(__dirname, 'pages/product-category/_slug/index.vue')
})
}
},
Maybe because I am having the i18n module, maybe because I am doing something wrong.
This is my folder structure:
If I inspect my router.js file, I see the path shown twice:
This was my workaround, I just wish there was a simpler method. Plus it still works if you use nuxt i18n.
nuxt.config.js
router: {
extendRoutes (routes, resolve) {
const routesToAdd = [
{ // add your routes here
name: 'product-category-slug-material',
path: '/product-category/:slug/in/:material',
component: resolve(__dirname, 'pages/product-category/_slug/index.vue'), // which component should it resolve to?
chunkName: 'pages/product-category/_slug/_material/index' // this part is important if you want i18n to work
}
];
const existingRoutesToRemove = routesToAdd.map(route => route.name);
const generateRoutes = routes.filter((route) => {
return !existingRoutesToRemove.includes(route.name);
});
routesToAdd.forEach(({ name, path, component, chunkName }) => {
generateRoutes.push({
name,
path,
component,
chunkName
});
});
routes.splice(0, routes.length, ...generateRoutes); // set new array
}
},
You can use _.vue to catch everything.
If you do not know the depth of your URL structure, you can use _.vue to dynamically match nested paths. This will handle requests that do not match a more specific request.
Here you can find out more.

How to initiate refresh of Vuejs page elements w/ new data?

I have a vuejs app using vue-router with the following routes.
const routes = [
{ path: '/list', component: list, alias: '/' },
{ path: '/resources/:id?', component: resources },
{ path: '/emails', component: emails },
{ path: '/list/:id', component: editHousehold, props: true },
{ path: '/list/turn-off/:id', component: editHousehold, props: true }
]
The first time the page loads the start event calls /resources w/o an ":id" and the page loads a list of resources (see below).
start: function () {
this.$http.get('/resources')
.then((res) => {
let gdriveInfo = res.data;
this.files = gdriveInfo.files;
}
);
},
Resource1
Resource2
Rescouce3
...
When the user clicks on one of the resources in the list I want to have /resources/1 called so a different set of resource data can be loaded and displayed.
I have a file click event attached to each resource where the "id" is appended to the path. This calls the server side module which would retrieve new data which would replace the "files" data in the component which I would expect would cause vuejs to "react" and update the contents of the page.
onFileClick: function (id, mimeType, event) {
const _this = this;
this.$http.get('/resources/' + id)
.then((res) => {
let gdriveInfo = res.data;
this.files = gdriveInfo.files;
}
);
}
However, calling above does not initiate a call to the server module.
this.$http.get('/resources/' + id)
I've also tried
this.$router.push('/resources/' + id)
which did not work.
Being new to vuejs, any help in how to achieve this functionality would be appreciated.
You lack host, because this.$http.get('/resources/' + id) is u component resources, this not json...
It looks like you're not making the REST call correctly. I think you're getting routing and REST calls mixed up. What you show above is for routing not making calls to the server.
You're not calling the server here:
this.$http.get('/resources/' + id)
and doing this is just for the routing:
this.$router.push('/resources/' + id)
Look at using axios for REST calls:
https://github.com/axios/axios

How to access current route meta fields in common javascript module - VueJs

I have following route in my application:
const router = new Router({
mode: 'history',
scrollBehavior: () => ({ y: 0 }),
routes: [
{ path: '/', component: HomePage, meta: { pageType: 'home'} },
],
});
and have on common js module:
const trackEvent = {
getFields: () => {
//here need to access meta fields(pageType) of current route. how is it possible ?
}
}
export default trackEvent;
i want to access meta field in common module. how is it possible ?
The meta property is accessible via this.$route.meta on a Vue instance. Just pass that to the getFields method.
export default {
created() {
let meta = getFields(this.$route.meta);
}
}
getFields: (meta) => {
console.log(meta);
return meta.fields.pageType; // not sure what you're trying to return exactly
}
If you can't pass in the current route, you'll need to import the router object and get the current route from that:
import router from 'path/to/your/router'
const trackEvent = {
getFields: () => {
let meta = router.currentRoute.meta;
console.log(meta);
return meta.fields.pageType; // not sure what you're trying to return exactly
}
}
export default trackEvent;

is it possible to specify which component should be used on router.go() in VueJS

In VueJS im trying to setup a scenario where the component used is determined by the url path without having to statically map it.
e.g.
router.beforeEach(({ to, next }) => {
FetchService.fetch(api_base+to.path)
.then((response) => {
router.app.$root.page = response
// I'd like to specify a path and component on the fly
// instead of having to map it
router.go({path: to.path, component: response.pageComponent})
})
.catch((err) => {
router.go({name: '404'})
})
})
Basically, I'd like to be able to create a route on the fly instead of statically specifying the path and component in the router.map
Hope that make sense. Any help would be appreciated.
I think that what you're trying to archive is programmatically load some component based on the current route.
I'm not sure if this is the recommended solution, but is what comes to my mind.
Create a DynamicLoader component whit a component as template
<template>
<component :is="CurrentComponent" />
</template>
Create a watch on $route to load new component in each route change
<script>
export default {
data() {
return {
CurrentComponent: undefined
}
},
watch: {
'$route' (to, from) {
let componentName = to.params.ComponentName;
this.CurrentComponent = require(`components/${componentName}`);
}
},
beforeMount() {
let componentName = this.$route.params.ComponentName;
this.CurrentComponent = require(`components/${componentName}`);
}
}
</script>
Register just this route on your router
{ path: '/:ComponentName', component: DynamicLoader }
In this example I'm assuming that all my componennt will be in components/ folder, in your example seems like you're calling an external service to get the real component location, that should work as well.
Let me know if this help you
As par the documentation of router.go, you either need path you want to redirect to or name of the route you want to redirect to. You don't the component.
Argument of router.go is either path in the form of:
{ path: '...' }
or name of route:
{
name: '...',
// params and query are optional
params: { ... },
query: { ... }
}
so you dont need to return component from your API, you can just return path or name of route, and use it to redirect to relevant page.
You can find more details here to create named routes using vue-router.