In this project we practice some concept regarding to routes
- Lazy loading
- Preloading
- Guards & Resolvers
- Interceptors
- Providers
Run ng serve
for a dev server. Navigate to http://localhost:4200/
. The application will automatically reload if you change any of the source files.
We have several ways to lazy load routes.
If the routes are from a Module
const routes: Routes = [
{
path: 'items',
loadChildren: () => import('./items/items.module').then(m => m.ItemsModule)
}
];
If the route is from a component
const routes: Routes = [
{
path: 'items',
loadComponent: () => import('./items/items.component).then(m => m.ItemsComponent)
}
];
Or you can lazy load from a routes file
const routes: Routes = [
{
path: 'items',
loadChildren: () => import('./items/items.routes').then(m => m.ITEMS_ROUTES)
},
];
In module based applications you can set a preloading strategy in the forRoot
method of RouterModule
import { PreloadAllModules } from '@angular/router';
RouterModule.forRoot(
appRoutes,
{
preloadingStrategy: PreloadAllModules
}
);
Standalone apps you can use withPreloading
within the provideRouter
function
import { ApplicationConfig } from '@angular/core';
import {
PreloadAllModules,
provideRouter
withPreloading,
} from '@angular/router';
import { routes } from './app.routes';
export const appConfig: ApplicationConfig = {
providers: [
provideRouter(
routes,
withPreloading(PreloadAllModules)
),
],
};
Note: You can apply your custom preloading strategies.
These are the current available guards:
canActivate
canActivateChild
canDeactivate
canMatch
resolve
To use a guard function in a Route element:
{
path: '/your-path',
component: YourComponent,
canActivate: [yourGuardFunction],
}
The defined function
export const yourGuardFunction: CanActivateFn = (
next: ActivatedRouteSnapshot,
state: RouterStateSnapshot) => {
// your logic goes here
}
Note: You can use inline function
A resolver let you fetch data before enter a route
import { Resolve } from '@angular/router';
...
/*An interface that represents your data model*/
export interface Crisis {
id: number;
name: string;
}
export class CrisisDetailResolverService implements Resolve<Crisis> {
resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<Crisis> {
// your logic goes here
}
}
Add a resolve object to the component's route configuration.
const var = {
path: '/your-path',
component: YourComponent,
resolve: {
crisis: CrisisDetailResolverService
}
}
then in your component
import { ActivatedRoute } from '@angular/router';
@Component({ … })
class YourComponent {
constructor(private route: ActivatedRoute) {}
ngOnInit() {
this.route.data
.subscribe(data => {
const crisis: Crisis = data.crisis;
});
}
}
They are function that you can run for each request. We can use inteceptors:
- Adding authentication tokens.
- Logging requests and responses.
- Handling global error messages.
- Modifying request/response formats.
- etc.
An example:
export function loggingInterceptor(req: HttpRequest<unknown>, next: HttpHandlerFn): Observable<HttpEvent<unknown>> {
return next(req).pipe(tap(event => {
if (event.type === HttpEventType.Response) {
console.log(req.url, 'returned a response with status', event.status);
}
}));
}
You can configure dependency providers
useClass
- this option tells Angular DI to instantiate a provided class when a dependency is injecteduseExisting
- allows you to alias a token and reference any existing one.useFactory
- allows you to define a function that build a dependency.useValue
- provides a static value that should be used as a dependency.
[{
provide: Logger,
useClass: BetterLogger
}]
[
NewLogger,
// Alias OldLogger w/ reference to NewLogger
{ provide: OldLogger, useExisting: NewLogger},
]
You can create a dynamic value based on information available in the DI and elsewhere in the app.
class HeroService {
constructor(
private logger: Logger,
private isAuthorized: boolean) { }
getHeroes() {
const auth = this.isAuthorized ? 'authorized' : 'unauthorized';
this.logger.log(`Getting heroes for ${auth} user.`);
return HEROES.filter(hero => this.isAuthorized || !hero.isSecret);
}
}
const heroServiceFactory = (logger: Logger, userService: UserService) =>
new HeroService(logger, userService.user.isAuthorized);
export const heroServiceProvider = {
provide: HeroService,
useFactory: heroServiceFactory,
deps: [Logger, UserService]
};
To inject values
import { InjectionToken } from '@angular/core';
export const APP_CONFIG = new InjectionToken<AppConfig>('app.config description');
providers: [{ provide: APP_CONFIG, useValue: MY_APP_CONFIG_VARIABLE }]
export class AppComponent {
constructor(@Inject(APP_CONFIG) config: AppConfig) {
this.title = config.title;
}
}
-
You can improve the session and permission management
-
A functionality to add favorite products