How to use component-nesting with vue-router? - javascript

I'm pretty new to Vue and I just can't find a good way how to use nested components alongside with vue-router.
What I have so far (some not-important code omitted):
index.html
<body>
<div id="app">
<router-view></router-view>
</div>
app.js
const router = new VueRouter({
routes: [{ path: '/login', component: Login }]
})
const app = new Vue({
router,
}).$mount('#app')
components/Login.vue
<template>
<h1>Please log in</h1>
</template>
This works perfectly well - I navigate to /login and it shows me the message in h1 tag. If I create more components, like Register or ResetPassword and add them to the router, it still works well. But the problem is that there is some repeating code in those components (for example, I want all the auth-related pages to have blue background) so I'd like to somehow create a "parent" component, that would define stuff that is same for all the "children" components. Something like:
Auth component (makes the page-background blue)
-> Login component (shows the login form)
-> Register component (shows the registration form)
I know I can do this through route's "children":
const router = new VueRouter({
routes: [
{ path: '/', component: Auth, children: [
{ path: '/login', component: Login }
{ path: '/register', component: Register }
]}
]
})
But with this configuration, there is the main route path: '/', which is completely wrong - I don't want it here - I don't want the Auth component to be used "standalone" - I want it just as a "wrapper" for the nested components.
What is the best way to solve this problem?

The way I've solved this issue is to use a base path redirect.
{ path: '', redirect: '/to/path' },
in your case it would be
const router = new VueRouter({
routes: [
{
path: '/',
component: Auth,
children: [
{ path: '', redirect: '/login' },
{ path: '/login', component: Login },
{ path: '/register', component: Register }
]
}
]
})
This ensures that

Related

Angular 9 : Children routing inside lazy loaded component not working

I have app component in which i lazy load create-new-module with component profilecomponent. now in profile component i hit router.navigate and trying to load another children detail in place of profile but its not working also no error in console.
please help
// App component route
const routes: Routes = [
{
path: 'create-new-emp',
loadChildren: () => import('./create-new-emp/create-new-emp.module').then(c => c.CreateNewEmpModule),
},
{ path: '', redirectTo: 'create-new-emp', pathMatch: 'full'},
{ path: '**', redirectTo: 'create-new-emp'}
];
// Emp Module Route
const routes: Routes = [
{ path: '', component: ContainerComponent,
children: [
{ path: '', component: ProfileComponent, outlet: 'form'},
{ path: 'profile', component: ProfileComponent, outlet: 'form'},
{ path: 'detail', component: DetailComponent, outlet: 'form' }] }
];
// Trying to hit below link but not working
this.router.navigate(['detail'])
<app-component>
<router-outlet>
<container-component>
<profile-component></profile-component>
</container-component>
</router-outlet>
</app-component>
Complicated with only these information to help. But is the way angular navigates amount components/pages. I think what you are trying to do is navigate between components (according your router.ts). If you want to navigate, you only need router-outlet in your html code and not use component tag in the HTML code.
Change this:
<app-component>
<router-outlet>
<container-component>
<profile-component></profile-component>
</container-component>
</router-outlet>
</app-component>
To this:
<app-component>
<router-outlet>
</router-outlet>
</app-component>
Then, into ContainerComponent.html you need to repeat to navigate to details o profile because these are child routes.
<router-outlet></router-outlet>
That will give you more information about what you need.
Its hard to say with this info, but may... you should define de router outlet name
<router-outlet name="form"></router-outlet>
Hope it's help.

Named router outlet doesn't render template in lazy loaded route

I have a problem with my angular 8 app, not rendering into a named router-outlet.
The routes are:
routes.module:
const routes: Routes = [
...
{
path: 'settings', loadChildren: './settings/settings.module#SettingsModule', canActivate
},
]
settings.module
RouterModule.forChild([
{
path: '', component: SettingsComponent
},
{
path: 'profile', component: ProfileComponent, outlet: 'settings_o'
},
{
path: 'users', component: UsersComponent, outlet: 'settings_o'
}
])
settings.component.html
<nav mat-tab-nav-bar color="primary" class="bg-whitesmoke primary">
<span mat-tab-link
*ngFor="let link of navLinks"
[routerLink]="[{outlets: {settings_o: [link.link]}}]"
routerLinkActive #rla="routerLinkActive"
[active]="rla.isActive">
{{link.label}}
</span>
</nav>
<router-outlet name="settings_o"></router-outlet>
When I click a link, the url in the address bar changes (e.g. to http://localhost:4200/settings/(settings_o:profile)), but no content is rendered to settings_o, nor do the components get loaded. There is no error in the console.
link.link is, for example simply profile like in settings.module's routes.
What do I need to change?
This is a known bug which has been discussed a lot: https://github.com/angular/angular/issues/10981
As far as I know it hasn't been solved completely but there are workarounds: https://github.com/angular/angular/issues/10981#issuecomment-454425220
You should give the lazy loaded module a default route and define the child routes for the components that you would like to open in the named outlet, for example:
RouterModule.forChild([
{
path: "default",
component: SettingsComponent,
children: [
{ path: "profile", component: ProfileComponent,outlet: "settings_o" },
{ path: "users", component: UsersComponent, outlet: "settings_o" }
]
}
]);
Of course you have to change the navigation to the SettingsComponent accordingly: routerLink='/settings/default'
I made a Stackblitz which is not an exact copy of your code but which shows how it can be solved: https://stackblitz.com/edit/angular-nctjpv
By the way, in your original solution, if you placed the named router outlet in the root component, I think it would display the child component but in the wrong place.

How to change VueRouter source file dynamicly?

Hello i have a project it contain multiple role (VueJs+Laravel), i'm using laravel as a back-end and vuejs as a front-end,
i have three diffrent role (User,Modirator,Editor).
this is my code in app.js
// VueRouter
import VueRouter from 'vue-router';
import routes from './routes.js';
Vue.use(VueRouter);
var router = new VueRouter({
mode: 'history',
routes
})
this is my routes file:
let routes = [
// General
{ path: '/about', component: require('./components/Home/About.vue').default },
{ path: '/pasword-change', component: require('./components/ChangePassword.vue').default },
// User
{ path: '/User', component: require('./components/User/Dashboard.vue').default },
// Modirator
{ path: '/Modirator', component: require('./components/Modirator/Dashboard.vue').default },
// Editor
{ path: '/Editor', component: require('./components/Editor/Dashboard.vue').default },
// Error
{ path: '*', component: require('./components/Errors/404.vue').default} },
]
export default routes
after login i want to check it in back-end as a ajax request if the role is user use (routes-user.js) elseif is a modirator use (routes-mod.js) else (routes.js).
i dont want to show /user /modirator /editor in client, but i want to check after login and each one show role component in root url /.
thanks for help.
thanks for help....
I tested something similar to your requirement for normal component passing and lazy loading component in Vuex and this works. Below is my code what I am trying to do is have a variable 'unauthorized' and based on which I an loading different component using javascript ternary operator or javascript template string.
import Vue from 'vue'
import Router from 'vue-router'
import Auth from './views/Auth.vue'
import Board from './views/Board.vue'
Vue.use(Router)
let unauthorized = true;
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/auth',
name: 'authenticate',
component: unauthorized ? Auth : Board
},
{
path: '/',
name: 'home',
component: () => import(`./views/${unauthorized ? 'Auth.vue': 'Board.vue'}`)
}
]
})
Specific Solution
As per your requirement, you can store a variable('access-type') in local storage based on whether you log in as 'moderator' or 'user' or 'editor' and then fetch it in router.js file and use template string feature to conditionally change the component path.
Do let me know if you need more help.
You could add meta data to your routes to solve the problem and the check the meta data before you're entering a route:
{ path: '/about', component: require('./components/Home/About.vue').default },
{ path: '/pasword-change', component: require('./components/ChangePassword.vue').default },
// User
{ path: '/User', component: require('./components/User/Dashboard.vue').default, meta: {authorize: ["Admin"]} },
Then add the following method to you router:
router.beforeEach((to, from, next) => {
const { authorize } = to.meta
// get currently logged in user (in my case it's coming from vuex)
const currentUser = store.getters['authentication/user']
if (!currentUser && to.path !== '/login') {
// not logged in so redirect to login page with the return url
return next({ path: '/login', query: { returnUrl: to.path } })
}
if (authorize) {
// check if route is restricted by role
if (authorize.length && !authorize.some(r => currentUser.roles.includes(r))) {
// role not authorised so redirect to home page
return next({ path: '/' })
}
}
next()
})

Angular 4 load child route in root outlet

I have a standard admin layout, where all main tabs are lazy loaded modules with separate state management. This is all wrapped in admin component with sidebar and router-outlet. One of my lazy-loaded admin tabs has a special component, which is supposed to open a full-screen preview of a product, occupying admin sidebar and navbar with it's own content.
My app router looks something like this:
export const appRoutes: Routes = [
/// ... some routes
{ path: 'admin', component: AdminComponent, canActivate: [SignedInGuard], children: [
/// ... some admin child routes
{ path: 'scrapers', loadChildren: '../scrapers/scrapers.module#ScrapersModule'}
/// ... some admin child routes
]}
/// ... some routes
]
And my scrapers module routes look like this:
export const scrapersRoutes: Routes = [
{ path: '', component: ScrapersListComponent },
{ path: 'single/:version', component: SingleScraperComponent, children: [
{ path: '', redirectTo: 'statistics', pathMatch: 'full' },
{ path: 'statistics', component: ScraperStatisticComponent },
{ path: 'targets', component: ScraperTargetsComponent },
]},
{ path: 'compare', component: CompareScrapersComponent },
{ path: 'preview', component: ScrapersPreviewComponent }
];
My goal is to open preview route of the scrapers module on the same outlet as admin.
My ideas for now:
a) overkill with html/css (very bad idea)
b) create a separate module for preview. Sounds resolute, but it hardly depends on scrapers lazy-loaded state, so I would not do this
c) load preview in a higher hierarchy outlet. If there is a valid way to do it, I would choose this.
Please, share your thoughts. Thanks!

Vue-Router Abstract Parent Routes

I am trying to migrate my current site to vuejs. The site map must be:
/login
/signup
/password-reset
/browse
/search
... dozens of other routes
As some of these routes share a lot of fx, I've made them the children of parent routes:
[{ // public routes
path: '/',
component: Auth,
children: [
{ path: '/login', component: Login },
{ path: '/signup', component: Signup },
{ path: '/password-reset', component: PasswordReset },
]
},
{ // routes behind Authentication
path: '/',
component: Home,
children: [
{ path: '/browse', component: Browse },
{ path: '/search', component: Search }
]
}]
The problem is obvious: The Auth and Home base components now are technically the same route path and I get routing errors. Since I will have a lot of routes sharing the same base component and fx, I'd like to have them be children of these abstract states.
Question 1: How can I implement these routes and their parent abstract states without conflict and without having to add all the wrapping logic to the children?
Question 2: How can I make it so the parent states () are not routeable or if they are, the default to a child state?
Whenever more than one route shares the same path, the first route in the array takes priority. So you need to put the Home route before the Auth route. That way, the / path will always match the Home route and not the Auth route. That also means that it is impossible to route directly to the Auth route, which is what you want.
If you do not want the Home route to be accessible, you can specify a redirect that should occur when it is matched exactly:
{
path: '/',
component: Home,
redirect: '/browse', // Redirect to path, or
redirect: { name: 'browse' }, // Redirect to named route
children: ...
}
If your Auth component has no auth-specific UI, you mightn't want to use "abstract" routes like this to enforce the authentication. There's plenty of information about how to achieve this in vue-router; here's one way:
// Routes
{
path: '/profile',
component: Profile,
meta: { auth: true },
}
// Router hooks
router.beforeEach((to, from, next) => {
if (to.matched.some(route => route.meta.auth) && !authenticated) {
next('/login');
} else {
next();
}
});

Categories

Resources