I have two url format
example.com/posts/:postId
and example.com/posts/:postId/:postTitle
just like stack-overflow individual question url.
In angular route I need to redirect all the urls with :postId
to :postId/:PostTitle
or directly loading the page with :postId/:PostTitle
lands to same page.
post.module.ts
const routes: Routes = [
{
path: ':postId',
resolve: {data: PdResolver},
redirectTo: ':postId/:PostTitle',
pathMatch: 'full'
},
{
path: ':postId/:PostTitle',
component: PostComponent,
data: {
title: 'This has to be the post fetched title'
}
}
];
redirectTo: ':postId/:PostTitle'
: here I don't have a postTitle so it throws errorI don't have the title so first I need to get postTitle using the postId, so we have a post data resolver (PdResolver),
Question Update: For a workaround:
I tried with child component which at least solves the case but still wondering if this is the approach I should follow or not.
{
path: ':postId',
component: PostOutletComponent,
resolve: {data: PdResolver},
children: [
{
path: ':postTitle',
component: PostComponent,
}]
}
And in PostOutletComponent
I am navigating further to child component after fetching the title
PostOutletComponent.ts
static stripHtml(html: string) {
let div = document.createElement('DIV');
div.innerHTML = html;
const cleanText = div.innerText;
div = null;
return cleanText;
}
ngOnInit() {
this.reolveData = this._route.snapshot.data;
let postTitle = PostOutletComponent.stripHtml(
this.reolveData.data.data.post_title);
postTitle = postTitle.replace(/\s+/g, '-').toLowerCase();
this.router.navigate([postTitle], {relativeTo: this._route});
}
I made a Stackblitz based on your code: https://stackblitz.com/edit/angular-r1tvx2
It solves a problem which occurs if a user navigates to the URL with existing ID but wrong title. In the above example the title is corrected as Stack Overflow does.
I made it using only one resolver and one component class. The Resolver takes care of redirecting to the correct URL. Note that the Resolver is placed in the more specific route with title.
Route configuration, the order of the routes is important, first comes the more specific route with title:
{
path: "posts/:id/:title",
component: PostComponent,
resolve: { somedata: PostDetailResolverService }
},
{
path: "posts/:id",
redirectTo: "posts/:id/title-to-be-repalced",
},
{ path: "**", component: PageNotFoundComponent }
];
Resolver, redirects to the URL with the correct title:
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<Somedata> | Observable<never> {
let id = +route.paramMap.get("id");
let title = route.paramMap.get("title");
return this.getData(id).pipe(
take(1),
mergeMap(res => {
if (res) {
console.log("Resolver - Navigation continues to the route with data:", res);
if (!title || title != res.title) {
this.router.navigate(["posts/" + res.id + "/" + res.title]);
}
return of(res);
} else {
// id not found
console.log("Navigation cancelled");
this.router.navigate([""]);
return EMPTY;
}
})
);
}