I am learning use of multiple router-outlet.
While using navigateBy function of router, i am not able to view my child route and getting error. But if i access it via routerLink in html i get the desired output.
So in below code, navigation to songs is working , but navigation to films is not.
const routes = [
{
path: 'bollywood',
component: BollywoodComponent,
children: [
{
path: 'films',
component: FilmsComponent,
},
{
path: 'songs',
component: SongsComponent,
},
],
},
{
path: 'hollywood',
component: HollywoodComponent,
},
{
path: 'tollywood',
component: TollywoodComponent
},
];
App Component html
<button class="f-margin-16" (click)="navigateToBollywoodSection()"> Bollywood </button>
<button class="f-margin-16" (click)="navigateToHollywoodSection()"> Hollywood </button>
<button class="f-margin-16" [routerLink]="['tollywood']" > Tollywood </button>
<br>
Router outlet starts now
<router-outlet> </router-outlet>
Bollywood Component html
<button (click)="navigateToFilms()"> Films </button>
<button [routerLink]="['songs']"> Songs </button>
<router-outlet> </router-outlet>
navigateToFilms() {
this.router.navigate(['/films']);
}
StackBitz Link
https://stackblitz.com/edit/angular-ivy-1nzkus?file=src/app/bollywood/bollywood.component.html
In router.navigate, you can pass relativeTo as the second param.
navigateToFilms() {
this.router.navigate(['films'], {relativeTo: this.activatedRoute} );
}
This way navigation will happen relative to the current route.
In the constructor you can add the ActivatedRoute dependency.
constructor(private activatedRoute: ActivatedRoute) {}
If you use <button [routerLink]="['songs']"> Songs </button>, the navigation by default happens relative to the current route.
Use it like this
this.router.navigate(['bollywood/films']);
If you want to use a navigation route then you can use this code.
because without a specific parent route you can't access child routing.
this.router.navigate(['/bollywood/films']);
Related
In my Angular 14 application I have tree on the left side which contains buildings and persons inside these buildings.
+ Building 1
- Person 1
- Person 2
- Person 3
+ Building 2
- Person 4
- Person 5
When I click an entry in the tree I want to display some details on the right side of the browser window. Therefore, I created a HTML template which contains the tree and a <router-outlet> for rendering the child components.
<div class="container">
<div class="tree-container">
...
</div>
</div>
<div class="content-container">
<router-outlet></router-outlet>
</div>
</div>
The routes are defined in this way:
const routes: Routes = [
{ path: '', component: MainComponent, canActivate: [AuthGuard],
children: [
{ path: 'building/:uuid', component: BuildingComponent},
{ path: 'person/:uuid', component: PersonComponent},
]
},
];
When I click an entry I call a method in the Maincomponent routing to the corressponding child compoment:
this.router.navigate(['building', buildingUuid], {relativeTo: this.route})
or
this.router.navigate(['person', personUuid], {relativeTo: this.route})
This works fine if I switch between building and person items. In this case the child component is shown in the right part of the browser window.
But when I click two nodes of the same type after each other (e.g. Person 1 and then Person 2) I see that the URL in the browser changes, but the child component is not updated.
Any ideas, what I'm doing wrong?
It's because you are already navigated to that component, so the component is already created and will not be created again.
What you should do is to subscribe to the params in the ngOnInit, so your logic will be executed on each param change:
import { ActivatedRoute} from '#angular/router';
...
constructor(private route: ActivatedRoute) {}
...
ngOnInit() {
this.route.params.subscribe({
next: (params) => {
const uuid = params.uuid;
// Your logic
},
error: (error) => {
console.log('ERROR: ', error);
},
});
}
Note: Don't forget to unsubscribe from Observable in ngOnDestroy.
Using the Nav on the website and going from
http://localhost:4200/mens
to
http://localhost:4200/mens/shirts
Works fine but when clicking on another category from with shirts like Hats the component/page doesn't reload and i'm unsure why as i'm not getting a error and it work fine when you click in the first category but within that category if you click on another it doesn't.
const routes: Routes = [
{
path : '',
component: WebsiteComponent,
children: [
{
path : '',
component: HomePageComponent,
},
{
path : 'mens',
component: MensPageComponent
},
{
path : 'mens/:category',
component: MensPageComponent
}
]
}
];
How are you getting your params in the men's component?
Here is a stackblitz that works https://stackblitz.com/edit/angular-buahdy
It uses route.params observable that emits when the route changes, if you are using a snapshot it will not change as it is not an observable.
category$ = this.route.params.pipe(map(params => params.category));
constructor(private route: ActivatedRoute) { }
and in the template show the category with the async pipe
Category {{ category$ | async }}
When you go from mens/shoes to mens/shirts the men's component does not reload, only the category param has changed. Subscribing to the param with route.params is how you trigger an update in your component.
When using the children property in the route. The component will need a router-outlet for those children routes to be rendered.
WebsiteComponent template:
<!-- some code -->
<!-- where children routes are rendered -->
<router-outlet></router-outlet>
I setup my Vue project to use dynamic layouts - that is, layouts that persist from page to page, assuming the layout for the new page is the same as the last page. My problem is that when I go to a route with a different layout, the router-link component gets created and destroyed, then created again, which is causing me some issues. My setup is as follows:
App.vue
<template>
<component :is="layout">
<router-view :layout.sync="layout" />
</component>
</template>
<script>
import LayoutPortal from '#/layouts/LayoutPortal';
import LayoutOffline from '#/layouts/LayoutOffline';
import LayoutDefault from '#/layouts/LayoutDefault';
export default {
name: 'App',
components: {
LayoutPortal,
LayoutOffline,
LayoutDefault,
},
...
Some router-view Component
<template>
...
</template>
<script>
import LayoutDefault from '#/layouts/LayoutDefault';
export default {
...
created() {
this.$emit('update:layout', LayoutDefault);
},
}
</script>
Layout Default
<template>
<div class="wrapper">
<slot />
</div>
</template>
<script>
export default {
name: 'layout-default',
};
</script>
tldr;
If you setup your project using dynamic layouts, following any of a number of tutorials out there online, when you navigate to a route with a different layout than the last page, the new router-view component gets created, destroyed, then created again. This causes issues like doubling up on mounted() calls and more.
I ultimately went with nested (child) routes (https://router.vuejs.org/guide/essentials/nested-routes.html):
{
path: '/portal',
component: LayoutPortal,
beforeEnter(to, from, next) {
if (!store.getters.auth) {
next('/login');
return;
}
next();
},
children: [
{
path: 'home',
name: 'portal-home',
component: PortalHome,
},
{
path: 'about',
name: 'portal-about',
component: PortalAbout,
},
...
In this way I can load up the layout as the parent route, separate beforeEnter logic into separate route groups, and avoid the problem where going to a page with a new layout loads a component twice.
I am new to Vue and I'm trying to learn how to apply Vue router. I got normal routing to work no problem. When I try to use dynamic routing everything continued to work fine. When I tried to pass props to dynamic routes however my code breaks.
I'm using these cdn versions of Vue and Vue router which are the versions suggested by the official websites:
- https://cdn.jsdelivr.net/npm/vue#2.5.16/dist/vue.js
- https://unpkg.com/vue-router#2.0.0/dist/vue-router.js
The HTML
<div id="app">
<h1>{{ message }}</h1>
<nav>
<router-link to="/">Home</router-link>
<router-link to="/about">About</router-link>
<router-link to="/user/John">Name</router-link>
</nav>
<!-- route outlet -->
<!-- component matched by route will render here -->
<router-view></router-view>
</div>
The JS
// Route components
const Home = { template: '<div>Home</div>' };
const About = { template: '<div>About</div>' };
const User = { props: ['name'], template: `
<div>
<div>User {{ name }}</div>
<button #click="checkName">Check</button>
</div>`,
methods: {
checkName: function() {
console.log('Params name: ' + this.$route.params.name);
console.log('Props name: ' + this.name);
}
}
};
// Routes for router
const routes = [
{ path: '/', component: Home },
{ path: '/home', redirect: Home },
{ path: '/about', component: About },
{ path: '/user/:name', component: User, props: true }
];
const router = new VueRouter({
routes: routes
});
const app = new Vue({
el: '#app',
data: {
message: 'VueJS Router'
},
router: router
});
When I navigate to the 'Name' page the static text renders fine but the dynamic text fails to load. I added a button that will log the value of name from props and from $route.params to the user. When clicked it turns out that the value of name in props is undefined but the value of name from params is correct. Why is this?
If you're sticking with VueRouter#2.0.0 or lower :
The name that you expect is not passed as a prop but as a route param, cf. Dynamic route matching.
You need to access it from your template as follow : $route.params.name.
You could also use a computed value instead.
If you can update VueRouter
As stated in another answer, and according to the release note of VueRouter#2.2.0, passing down route params as props has only been introduced in v2.2.0, you were using v2.0.0. If you would like to use props you would need to update to (at least) v2.2.0.
CDN link provided on the Vue Router installation page was outdated. Instead of:
https://unpkg.com/vue-router#2.0.0/dist/vue-router.js
use:
https://unpkg.com/vue-router#3.0.1/dist/vue-router.js
Answer provided here:
https://forum.vuejs.org/t/why-is-component-props-undefined-vue-router/34929/5
My sample Demo
i"m new in angularjs 2
how to show twitter names for corresponding names using routes in same page using second <router-outlet></router-outlet>
tried routing for child one (sample one not for this app)
children: [{path: 'child-one', component: ApplicationSecondComponent},
First of all you need to have default child route, so use next route configuration:
export const AppRoutes: Routes = [
{ path: '', component: ContactsListComponent, children: [{
path: '',
component: ContactsDetailComponent
}, {
path: 'contact/:id',
component: ContactsDetailComponent,
resolve: {
contact: 'contact'
}
}]
}
];
So you should control contact empty state using *nfIf directive also in your details component
<div *ngIf="contact">
<h2>{{contact.name}}</h2>
<dl>
<dt>Twitter</dt>
<dd>{{contact.twitter}}</dd>
</dl>
<p><a routerLink="/">Back to list</a></p>
</div>
And additional routing outlete inside list template
<ul>
<li *ngFor="let contact of contacts | async">
<a [routerLink]="['contact', contact.id]">{{contact.name}}</a>
</li>
</ul>
<router-outlet></router-outlet>
Also be careful - you need to move your contact resolve login into details component as you need to react to url params chages. This code will works only one:
this.contact = this.route.snapshot.data['contact'];
Please review updated plunker https://plnkr.co/edit/ZgbBKaF58brxILueKkxv?p=preview