This content originally appeared on Bits and Pieces - Medium and was authored by Kamil Konopka
Get rid of the deprecated implementation of the Resolve<T> class-based data provider in favor of the functional ResolveFn<T>.
Whenever we wanted to get data based on our parameters/query parameters, we couldn’t consider any better solution than Resolver. It was always a useful mechanism in Angular, providing a nice separation for getting the data and actually handling it within the component.
Resolver assures data availability before navigation ends. Actually, router waits with navigation end event emission until the data is there. Then all you need to do is to subscribe to activatedRoute.data in order to use it within your component directly.
Resolver always had to implement Resolve interface which required (and still is!) resolve method, which was returning either:
Observable<MyDataType> | Promise<MyDataType> | MyDataType
If you’re using Observable pattern to provide the data, make sure your stream completes! Otherwise, you will never see your component!
Class-based resolvers have been already deprecated in the Angular v15 release, but now with version 16, when the functional approach is even more common, it makes sense to switch to the ResolveFn type definition (in case you haven’t done it yet!).
There is no difference in returned type in both approaches. Nothing has changed there. Instead of the class implementation, we will use function/function expression instead.
The benefit of using a functional approach is no need to add created resolver into the providers array!
💡 As an aside, consider using an open-source tool such as Bit to store your reusable Angular components. You can then reuse this component across multiple projects using a simple bit import your.username/yourComponent command.
Learn more:
Ok, let’s have a look at the class-based implementation:
import { ActivatedRouteSnapshot, Resolve, RouterStateSnapshot } from '@angular/router';
import { Post } from '../models';
import { filter, Observable, take } from 'rxjs';
import { inject } from '@angular/core';
import { PostsFacade } from '../../store/posts';
export class PostResolver implements Resolve<Post> {
constructor(private readonly postsFacade: PostsFacade) {}
resolve(
route: ActivatedRouteSnapshot,
state: RouterStateSnapshot
): Observable<Post> {
const id = route.paramMap.get('id');
return this.postsFacade.getOne(id)
.pipe(
filter<Post>((post: Post) => !!post),
take(1));
}
}
ActivatedRouteSnapshot is being used to get the value of id parameter from actual URL. Then, postFacade is being called to get post data I need, making sure, my stream will be closed after the first emitted value. Not to forget to hook it up to the route definition:
{
path: 'blog/:id',
loadComponent: () => import('./blog/index').then(x => x.PostComponent),
resolve: { post: PostResolver },
},
Let’s compare it with the functional version:
import { ActivatedRouteSnapshot, ResolveFn, RouterStateSnapshot } from '@angular/router';
import { Post } from '../models';
import { inject } from '@angular/core';
import { PostsFacade } from '../../store/posts';
import { filter, take } from 'rxjs';
export const PostResolver: ResolveFn<Post> = (
route: ActivatedRouteSnapshot = inject(ActivatedRouteSnapshot),
state: RouterStateSnapshot = inject(RouterStateSnapshot),
postsFacade: PostsFacade = inject(PostsFacade)
): Observable<Post> => postsFacade.getOne(route.paramMap.get('id'))
.pipe(
filter<Post>((post: Post) => !!post),
take(1)
);
Now, I got rid of the deprecated implementation of Resolve<T> class-based data provider in favor of functional ResolveFn<T>.
Finally, I can use resolved data within PostComponent!
import { Component, inject, OnInit } from '@angular/core';
import { ActivatedRoute } from '@angular/router';
import { map, Observable, of } from 'rxjs';
import { Post } from '../../models';
import { AsyncPipe } from '@angular/common';
@Component({
selector: 'app-post',
standalone: true,
templateUrl: './post.component.html',
styleUrls: ['./post.component.scss'],
imports: [AsyncPipe],
})
export class PostComponent implements OnInit {
post$: Observable<Post | null> = of(null);
private readonly route: ActivatedRoute = inject(ActivatedRoute);
ngOnInit(): void {
this.post$ = this.route.data.pipe(map(({ post }) => post));
}
}
Quick and simple right?
Build Angular Apps with reusable components, just like Lego
Bit’s open-source tool help 250,000+ devs to build apps with components.
Turn any UI, feature, or page into a reusable component — and share it across your applications. It’s easier to collaborate and build faster.
Split apps into components to make app development easier, and enjoy the best experience for the workflows you want:
→ Micro-Frontends
→ Design System
→ Code-Sharing and reuse
→ Monorepo
Learn more:
- Introducing Angular Component Development Environment
- 10 Useful Angular Features You’ve Probably Never Used
- Top 8 Tools for Angular Development in 2023
- Getting Started with a New Angular Project in 2023
- How We Build Micro Frontends
- How to Share Angular Components Between Projects and Apps
- How we Build a Component Design System
- Creating a Developer Website with Bit components
How I’ve Replaced Deprecated Resolvers in Angular 16 was originally published in Bits and Pieces on Medium, where people are continuing the conversation by highlighting and responding to this story.
This content originally appeared on Bits and Pieces - Medium and was authored by Kamil Konopka
Kamil Konopka | Sciencx (2023-06-07T06:29:05+00:00) How I’ve Replaced Deprecated Resolvers in Angular 16. Retrieved from https://www.scien.cx/2023/06/07/how-ive-replaced-deprecated-resolvers-in-angular-16/
Please log in to upload a file.
There are no updates yet.
Click the Upload button above to add an update.