Angular access methods of parent routes from child routes - javascript

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

Related

Angular 14: Routing to child route not working properly

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.

How to keep route parameters even page refresh

I use the following approach to pass parameters through different routes and I am trying to keep these parameter values on page refresh or opening another tab on the routed page. However, after retrieving these parameters, they lost their values. So, is it possible to keep their values without using :id etc suffix on the routes? In this scenario, I open the SecondComponent first and then open its Child called SecondChildComponent using tabs.
first.component.ts
details(name) {
this.router.navigate(['/second'], { state: { name: name} });
}
second.component.ts
constructor(private router: Router) {
this.name= this.router.getCurrentNavigation().extras.state.name;
}
routing.module
const routes: Routes = [
{
path: 'second',
component: SecondComponent,
children: [
{
path: '',
redirectTo: 'second-child',
},
{
path: 'second-child',
component: SecondChildComponent
}
]
}
];
I'm afraid that your code don't work as you expect, please read this link about pass data using state
The brief idea is that you can get the value of the state
In the component where you go
ngOnInit() {
this.activatedRoute.paramMap
.pipe(map(() => window.history.state)).subscribe(res=>{
console.log(res)
})
}
In the "main component" using
ngOnInit() {
this.router.events.pipe(
filter(e => e instanceof NavigationStart),
map(() => this.router.getCurrentNavigation().extras.state)
).subscribe(res=>{
console.log(res)
})
}
Well about your question, the only "object" that maintain when you change the route is a "service". The only "object" that maintain when you "refresh" is localStore -or use some king of back-up in the server.
Using a service, simply has
#Injectable({
providedIn: 'root',
})
export class DataService {
data:any;
constructor() { }
}
And use
.subscribe(res=>{
this.dataService.data=res.name || this.dataService.data
this.name=this.dataService.data
})
Another aproach is if you don't receive a parameter router to first component. This idea can use e.g. if you has a typical component with a table with a button edit that links to a "detail" component. If the "detail" don't receive the value route to the component with the table
.subscribe(res=>{
if (!res.name)
this.router.navigateTo(['/table'])
})

modular routing in vuejs

I am building a simple website in which I have a route to category pages. I want to use a single dynamic route to move between pages.I am using vue-router for this project and the routes need to load different component
These are the desired routes for the website
example: '/shop/men' , '/shop/women','/shop/kids'
This my index.js file for router in which gender is appended in the last deciding which component to load the issue I am facing is how to handle this and load different component on depending on it
router-> index.js:
{
name: 'shop',
path: '/shop/:gender',
component: menCategoryViewsHandler('mencategory')
}
views -> viewHandler -> mencategory.js:
'use strict'
import Handle from '../mencategory.vue'
const camelize = str => str.charAt(0).toUpperCase() + str.slice(1)
// This is a factory function for dynamically creating root-level views,
// since they share most of the logic except for the type of items to display.
// They are essentially higher order components wrapping the respective vue file.
export default function ViewsHandler (type) {
console.log('1',type)
return {
name: `${type}-mencategory-view`,
asyncData ({store, route}) {
//#todo : add the ssr and routerbefore load change script here
return Promise.resolve({})
},
title: camelize(type),
render (h) {
return h(Handle,
{
props: {type},
},
)
},
}
}
You need to use dynamic route matching along with a wrapper component which renders the correct Category component. This would handled by passing props to components.
// CategoryResolver.vue
import menCategory from './mencategory'
import womenCategory from './womencategory'
import kidsCategory from './kidscategory'
const components = {
menCategory,
womenCategory,
kidsCategory
}
export default {
functional: true,
props: ['category'],
render(h, ctx) {
return h(`components[${category}Category`], ctx.data, ctx.children)
}
}
Then your router would be defined as such:
const router = new VueRouter({
routes: [
{ path: '/shop/:category', component: CategoryResolver, props: true }
]
})
Say menCategoryViewsHandler('mencategory') returns a component called MenCat. It must have a prop that matches the route above, in this example category. In MenCat you would define:
export default {
props: ['category'],
...
}
Vue router will pass the matching url prop into your component for you.

Angular: Child Route Matching

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.

How to configure Vue router to respond to query strings?

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.

Categories

Resources