I am trying to add a nested url to my routes. So far, every route works fine except for the last one (see code below).
I also tried nesting the urls (using the children property), but was unsuccessful with that, and I don't think that's the approach I want to take here anyway, since I want to use an entirely separate component, and not nest the <router-view>s.
Any suggestions for what I should do? I'm not even sure how to debug. The Vue dev tools just show a <RouterView> component, with one prop: name: "default".
Here is my routes.js file:
import VueRouter from 'vue-router';
import Search from './views/Search';
import FoodItem from './views/FoodItem';
import NutrientCategory from './views/NutrientCategory';
import NutrientDetail from './views/NutrientDetail';
let routes = [
{
path: '/',
component: Search
},
{
path: '/:id',
component: FoodItem
},
{
path: '/nutrients/:slug',
component: NutrientCategory
},
{
path: '/nutrients/:slug/:nutrient-slug',
component: NutrientDetail
}
]
export default new VueRouter({
routes,
linkActiveClass: 'active',
scrollBehavior (to, from, savedPosition) {
return { x: 0, y: 0 }
}
});
The problem is that you try to use the minus sign as the parameter name:
/nutrients/:slug/:nutrient-slug
But the regular expression from the path-to-regexp package for parsing the path-pattern uses the \w character classe as the name-pattern:
\w+ matches any word character (equal to [a-zA-Z0-9_])
So use underscore instead of minus:
/nutrients/:slug/:nutrient_slug
[ https://jsfiddle.net/fhrekL25/ ]
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 />
);
};
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.
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
I am trying to understand how named routes work. I am trying to establish 2 router outlets. Here is the actual error that I am getting...
EXCEPTION: Uncaught (in promise): Error: Cannot match any routes. URL Segment: 'song/edit/58ab2f3907dc8edf2c4e6971'
Here are code snippets that show what I am trying to do...
app.routing.ts
const appRoutes: Routes = [
{ path: 'songs', component: SongsComponent},
{ path: 'song/edit/:id', component: SongsComponent, outlet: "details" }
];
app.component.ts
#Component({
template: `
<button (click)="showDetail($event,song)">Show Detail</button>
<router-outlet>Songs Here</router-outlet>
<router-outlet name="details">Song Detail Here</router-outlet>
`
export class AppComponent {
showDetail(event: any,song: Song) {
event.stopPropagation();
let link = ['/song/edit', song._id];
this.router.navigate(link);
}
}
});
As a side note, what I ultimately want to do is keep the SongsComponent in the DOM when I navigate to the SongComponent. With 2 router-outlets the SongsComponent will remain in the DOM where I can hide and show it without having to regenerate the DOM for the SongsComponent if it used the same router-outlet as the SongComponent.
Since you are trying to route to Named route, you need to mention same in the router command,
try below,
showDetail(event: any,song: Song) {
event.stopPropagation();
let link = [{
outlets: {
details: ['song','edit',song._id]
}
}];
this.router.navigate(link);
}
Here is the Plunker!!
Hope this helps!!
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.