Suppose we have the following routes:
{
path: 'a',
component: AComponent,
children: [
{
path: '',
component: BComponent
},
{
path: '',
component: CComponent,
children: [
{ path: '', component: DComponent }
]
}
]
}
And the following URL is pasted into the browser's address bar:
http://localhost:4200/a
Questions
How does the Router know what component to display?
Would all the four components (A, B, C, D) be displayed?
Where would each component be displayed?
Does every parent component always have its own RouterOutlet, so each component along a route of parent/child/grand-child/etc. gets displayed inside its parent's respective RouterOutlet?
Usually, when displaying a route with child routes, each component is displayed inside its parent RouterOutlet. But, if only AComponent had a RouterOutlet, where would BComponent, CComponent and DComponent be displayed?
Given that you aren't getting any sort of error the router will give you the first matching route it found. In this case BComponent. Only one component can be shown in a router outlet (to do otherwise you need something like auxRoute).
If CComponent had a route like 'c' you could access it from the route http://localhost:4200/a/c then you would get CComponent with DComponent in CComponents router outlet.
Hope that helps.
Related
I am testing React Router v6.4 with CreateBrowserRoute
Apparently, I'm running into a problem when I nest the routes deeper than 2 levels
Router Object
const router = createBrowserRouter([
{
path: "/",
element: <Root/>,
children: [
{
index: true,
element: <Index/>
},
{
path: "tasks",
element: <TaskIndex/>,
children: [
{
index: true,
element: <TaskQue/>
},
{
path: "task-que",
element: <TaskQue/>,
children: [
{
path: "dashboard",
element: <TaskDashboard/>,
},
]
},
]
},
],
},
]);
Basically, the path causing troubles is this path tasks/task-que/dashboard if I understand it all correctly it should map it like this tasks->task-que->dashboard(element) and then render the element set as the element key-value pair.
The route is working(ish), because if I remove the path: "dashboard" route and visit tasks/task-que/dashboard it will fail.
It seems a bit odd as it works very well in the second-level nesting.
If i change the parents element:
path: "task-que",
element: <TaskQue/>,
To
path: "task-que",
element: <TaskDashboard/>,
It will use TaskDashboard at both of these routes:
/tasks/task-que
/tasks/task-que/dashboard
Seems like I'm misunderstanding something or missing something, does anyone have any knowledge about deeper react-router nesting who can provide constructive tips or point out where I'm failing in my test?
Seems like the TaskQue component is missing rendering an Outlet component for any nested routes it is wrapping. Each level of routing depth, if wrapping routes to nest them, still needs to render its own Outlet for the nested routes.
const TaskQue = () => {
... logic ...
return (
... Task Queue UI JSX ...
<Outlet /> // <-- "./dashboard" and <TaskDashboard />
);
};
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.
I currently have a Vue.js component called Summoner.vue which is rendered thanks to the router when a user visits the following URL - http://localhost:8080/summoner/username
In that component I have a <div> element which triggers a method on click, that sends the user to a new URL - http://localhost:8080/summoner/username/match/4132479262 which renders a different component Match.vue. Like this:
<div #click='specificMatch(match.gameId)'>
specificMatch(gameId){
router.push('/summoner/' + this.summoner + '/match/' + gameId)
}
Now all I want to do is pass an object as props from the first component to the second one, but I'm not sure how to do that because I'm using the router. Normally I'd pass props like this - <summoner v-bind:match="match.id"></summoner> but I guess that doesn't work in my case since I'm using router.
And these are my routes:
export default new Router({
mode: 'history',
base: process.env.BASE_URL,
routes: [
{
path: '/',
name: 'home',
component: Home
},
{
path: '/summoner/:summonerName',
name: 'summoner',
component: Summoner
},
{
path: '/summoner/:summonerName/match/:matchId',
name: 'match',
component: Match
}
]
})
Here is how you can do it with vue-router props :
{
path: '/summoner/:summonerName',
name: 'summoner',
component: Summoner,
props : true // now you can pass props to this route
}
then when you want to navigate to it :
this.$router.push({ name : summoner , params : { summonerName : this.summoner , somedata : 'hello' etc ... }})
now summoner component will have access to all these params on its props :
// summoner.vue
export default {
props : ['somedata',...]
...
}
So to explain clearly my problem, I have a component for each of my entities in my application like Author component and Book component. And for each of them I will have two child which is a list component and a form component.
So basically my route configuration look like this :
export const routing = RouterModule.forRoot([
{
path: 'author', component: AuthorComponent,
children: [
{ path: 'author-list', component: AuthorListComponent },
{ path: 'author-form', component: AuthorFormComponent }
]
},
{
path: 'book', component: BookComponent,
children: [
{ path: 'book-list', component: BookListComponent },
{ path: 'book-form', component: BookFormComponent }
]
}
]);
In my AuthorComponent for example I have a method to delete an author that call the service :
deleteBadge = (event): void => {
// Call delete service
this._badgeService.delete(event).subscribe(
result => {
// Good
},
error => {
// Error
}
My question is how can I call that method from my route child (author list or form component) knowing that I can't call it like a normal child component using event.
PS: I put method (and many other) in the parent because I need to access to it in both child components and so to avoid redundancy.
Standard practice is to use a shared service for Component Interaction. However, if you still want to avoid using a shared service, you can use the Injector API.
In your child component, AuthorListComponent for example, do the following:
import { Injector } from '#angular/core';
import {AuthorComponent} from "./author.component";
// ....
constructor(private injector:Injector){
let parentComponent = this.injector.get(AuthorComponent);
parentComponent.deleteBadge('String passed from AuthorListComponent');
}
Here is a link to working demo.
Use a communication Service which unites several communication observables.
An example can be found in the official Angular docs: https://angular.io/guide/component-interaction#parent-and-children-communicate-via-a-service
My router in configured as follows. It works and does what it's supposed to.
import Demo1 from "../vuex_modules/demo/demo1.vue"
import Demo2 from "../vuex_modules/demo/demo2.vue"
export const routes = [
{ path: "/demo/demo1", component: Demo1 },
{ path: "/demo/demo2", component: Demo2 }
];
Now, I need to match me some query strings. When I click in one of the views routed to above, I want the object pushed to the router to look like this.
export default {
methods: {
clicky: function(row) {
this.$router.push({ path: "", query: { id: row } });
}
}
}
I want the new URL, with ?id=123 added, to lead to another page (while demo2.vue is the table view, demo2_id.vue is supposed to be displayed upon a click and present details for the particular row being clicked.
According to Vue router docs, I'm suppose to add a colon when a part of URL is dynamic. I've tried different approaches, including the one below. I'm not routed to the page requested, though. Instead, I dwell still on the original page.
import Demo1 from "../vuex_modules/demo/demo1.vue"
import Demo2 from "../vuex_modules/demo/demo2.vue"
import Demo2_Id from "../vuex_modules/demo/demo2_id.vue"
export const routes = [
{ path: "/demo/demo1", component: Demo1 },
{ path: "/demo/demo2", component: Demo2 },
{ path: "/demo/demo2?:id", component: Demo2_Id }
];
Goolearching for vue router query strings leads to nothing that I can regard as useful (possibly due to ignorance)...
Case 1:
Following routes are two same route:
{ path: "/demo/demo2", component: Demo2 },
{ path: "/demo/demo2?:id", component: Demo2_Id }
Case 2:
While following are different:
{ path: "/demo/demo2", component: Demo2 },
{ path: "/demo/demo2/:id", component: Demo2_Id }
In first case: /demo/demo2?:id=213, you can get id as $route.query.id while in second case: /demo/demo2/:id, you will get id as $route.params.id.
Now if you want to have routes as in case 1: You will have single row in routes file and single route:
{ path: "/demo/demo2", component: Demo2 },
and you can write code to detect whether $route.query.id is present or not and load component accordingly with use of v-if
If you want to have routes as in case 2: you can add above two lines in routes file and treat them as two different routes.