0%

What's new in Angular 15

Introduction

Tree-shakable router

You can build multiple routes applications with the new router standalone API.

Define the root routes in app.routes.ts, and use loadChildren to load the lazy routes.

1
2
3
4
5
6
// app.routes.ts
export const appRoutes: Routes = [{
path: 'lazy',
loadChildren: () => import('./lazy/lazy.routes')
.then(routes => routes.lazyRoutes)
}];

Define the lazy routes in lazy.routes.ts.

1
2
3
4
5
// lazy.routes.ts
import {Routes} from '@angular/router';
import {LazyComponent} from './lazy.component';

export const lazyRoutes: Routes = [{path: '', component: LazyComponent}];

Provide the router in file main.ts.

1
2
3
4
5
6
// main.ts
bootstrapApplication(AppComponent, {
providers: [
provideRouter(appRoutes) // tree-shakable
]
});

The benefit of provideRouter is that it is tree-shakable.

Directive composition API

这个我没太看懂,需要进一步研究它的来历。

1
2
3
4
5
6
7
8
9
@Component({
selector: 'mat-menu',
hostDirectives: [HasColor, {
directive: CdkMenu,
inputs: ['cdkMenuDisabled: disabled'],
outputs: ['cdkMenuClosed: closed']
}]
})
class MatMenu {}

NgOptimizedImage

NgOptimizedImage is a new directive that optimizes images for the web.
First, import NgOptimizedImage in your component.

1
2
3
4
5
import { NgOptimizedImage } from '@angular/common';
@Component({
imports: [NgOptimizedImage],
...
})

Then, replace src in img tag with ngSrc.

1
<img [ngSrc]="url" alt="image">

Functional router guards.

You can now use functional router guards.

Before:

1
2
3
4
5
6
7
8
9
10
11
12
13
@Injectable({ providedIn: 'root' })
export class MyGuardWithDependency implements CanActivate {
constructor(private loginService: LoginService) {}

canActivate() {
return this.loginService.isLoggedIn();
}
}

const route = {
path: 'somePath',
canActivate: [MyGuardWithDependency]
};

After:

1
2
3
4
const route = {
path: 'admin',
canActivate: [() => inject(LoginService).isLoggedIn()]
};

Route unwraps default imports

Before:
You need .then to unwrap the default import.

1
2
3
4
{
path: 'lazy',
loadComponent: () => import('./lazy-file').then(m => m.LazyComponent),
}

Now: with the default export enabled, you can directly use the default import.

1
2
3
4
{
path: 'lazy',
loadComponent: () => import('./lazy-file'), // <--- no need to unwrap manually.
}

You must use default export in the lazy file.

1
2
3
4
5
@Component({
standalone: true,
template: '...'
})
export default class LazyComponent { ... } // default export.

Automatic imports in language service.

When you type a component selector in the template, the language service will prompt to import the component for you.

CLI improvements

Generate standalone components with the following command

1
ng g component --standalone

Simplify the output of the ng serve command.

  1. Remove File test.ts, polyfills.ts, and environments
  2. Specify polyfills in angular.json
    1
    2
    3
    "polyfills": [
    "zone.js"
    ]

Global format for Date pipe

1
2
3
4
5
6
7
8
bootstrapApplication(AppComponent, {
providers: [
{
provide: DATE_PIPE_DEFAULT_OPTIONS,
useValue: { dateFormat: 'shortDate' }
}
]
});

Deprecations

  1. providedIn: 'any' is deprecated. Use providedIn: 'root' instead.
  2. providedIn: NgModule is deprecated. Use providedIn: 'root' or providedIn: NgModule instead.

Reference

  1. https://blog.angular.dev/angular-v15-is-now-available-df7be7f2f4c8