Skip to content

Commit 2cb5493

Browse files
authored
feat: add Standalone APIs category (#2)
1 parent 4607ead commit 2cb5493

9 files changed

+420
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
{
2+
"label": "Standalone APIs",
3+
"link": {
4+
"type": "generated-index",
5+
"description": "Guides for using Angular's Standalone APIs, including Standalone Components."
6+
}
7+
}
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
# Adding top-level routes to a standalone Angular application
2+
3+
## Interoperability using the RouterModule
4+
5+
As of Angular version 14.0.0-rc.0, there is no dedicated standalone API for the Angular router so we pass `RouterModule.forRoot` to the `importProvidersFrom` function:
6+
7+
```typescript
8+
import { enableProdMode, importProvidersFrom } from "@angular/core";
9+
import { bootstrapApplication } from "@angular/platform-browser";
10+
import { RouterModule, Routes } from "@angular/router";
11+
12+
import { AboutComponent } from "./app/about.component";
13+
import { AppComponent } from "./app/app.component";
14+
import { HomeComponent } from "./app/home.component";
15+
import { environment } from "./environments/environment";
16+
17+
if (environment.production) {
18+
enableProdMode();
19+
}
20+
21+
const routes: Routes = [
22+
{
23+
path: "",
24+
pathMatch: "full",
25+
redirectTo: "home",
26+
},
27+
{
28+
path: "home",
29+
component: HomeComponent,
30+
},
31+
{
32+
path: "about",
33+
component: AboutComponent,
34+
},
35+
];
36+
37+
bootstrapApplication(AppComponent, {
38+
providers: [importProvidersFrom(RouterModule.forRoot(routes))],
39+
}).catch((err) => console.error(err));
40+
```
41+
42+
## Future standalone API
43+
44+
In a future Angular version, a function creating the necessary providers will be available. It might look something like this:
45+
46+
```typescript
47+
import { enableProdMode } from "@angular/core";
48+
import { bootstrapApplication } from "@angular/platform-browser";
49+
import { Routes, withRoutes } from "@angular/router";
50+
51+
import { AboutComponent } from "./app/about.component";
52+
import { AppComponent } from "./app/app.component";
53+
import { HomeComponent } from "./app/home.component";
54+
import { environment } from "./environments/environment";
55+
56+
if (environment.production) {
57+
enableProdMode();
58+
}
59+
60+
const routes: Routes = [
61+
{
62+
path: "",
63+
pathMatch: "full",
64+
redirectTo: "home",
65+
},
66+
{
67+
path: "home",
68+
component: HomeComponent,
69+
},
70+
{
71+
path: "about",
72+
component: AboutComponent,
73+
},
74+
];
75+
76+
bootstrapApplication(AppComponent, {
77+
providers: [withRoutes(routes)],
78+
}).catch((err) => console.error(err));
79+
```
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
# Bootstrapping a standalone application
2+
3+
## Using the bootstrapApplication function
4+
5+
A standalone Angular application bootstraps a component often called the `AppComponent`, making it the root component of our application. We use the `bootstrapApplication` function to do this. It accepts the class of the root component as its first parameter and optionally an object with a `providers` property that contains an array of application-wide providers.
6+
7+
The following code block lists a simple `main.ts` file:
8+
9+
<!-- TODO(LayZeeDK): support code highlighting -->
10+
11+
```typescript
12+
import { enableProdMode } from "@angular/core";
13+
import { bootstrapApplication } from "@angular/platform-browser";
14+
15+
import { AppComponent } from "./app/app.component";
16+
import { environment } from "./environments/environment";
17+
18+
if (environment.production) {
19+
enableProdMode();
20+
}
21+
22+
bootstrapApplication(AppComponent).catch((err) => console.error(err));
23+
```
24+
25+
## Application-wide providers
26+
27+
To add a root-level provider, we can add it to the `providers` array:
28+
29+
```typescript
30+
import { enableProdMode } from "@angular/core";
31+
import { bootstrapApplication } from "@angular/platform-browser";
32+
33+
import { AppComponent } from "./app/app.component";
34+
import { environment } from "./environments/environment";
35+
36+
if (environment.production) {
37+
enableProdMode();
38+
}
39+
40+
bootstrapApplication(AppComponent, {
41+
providers: [AuthService],
42+
}).catch((err) => console.error(err));
43+
```
44+
45+
## Using providers from NgModules
46+
47+
To provide root-level providers using an NgModule, we pass the NgModule to the `importProvidersFrom` function.
48+
49+
For example, we can provide the `HttpClient`'s dependencies as shown in the following listing:
50+
51+
```typescript
52+
import { HttpClientModule } from "@angular/common/http";
53+
import { enableProdMode, importProvidersFrom } from "@angular/core";
54+
import { bootstrapApplication } from "@angular/platform-browser";
55+
56+
import { AppComponent } from "./app/app.component";
57+
import { environment } from "./environments/environment";
58+
59+
if (environment.production) {
60+
enableProdMode();
61+
}
62+
63+
bootstrapApplication(AppComponent, {
64+
providers: [importProvidersFrom(HttpClientModule)],
65+
}).catch((err) => console.error(err));
66+
```
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Enabling animations in a standalone Angular application
2+
3+
## Interoperability using the BrowserAnimationsModule
4+
5+
As of Angular version 14.0.0-rc.0, there is no dedicated standalone API for Angular browser animations so we pass `BrowserAnimationsModule` to the `importProvidersFrom` function:
6+
7+
```typescript
8+
import { enableProdMode, importProvidersFrom } from "@angular/core";
9+
import { bootstrapApplication } from "@angular/platform-browser";
10+
import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
11+
12+
import { AppComponent } from "./app/app.component";
13+
import { environment } from "./environments/environment";
14+
15+
if (environment.production) {
16+
enableProdMode();
17+
}
18+
19+
bootstrapApplication(AppComponent, {
20+
providers: [importProvidersFrom(BrowserAnimationsModule)],
21+
}).catch((err) => console.error(err));
22+
```
23+
24+
## Future standalone API
25+
26+
In a future Angular version, a function creating the necessary providers will be available. It might look something like this:
27+
28+
```typescript
29+
import { enableProdMode } from "@angular/core";
30+
import { bootstrapApplication } from "@angular/platform-browser";
31+
import { withAnimations } from "@angular/platform-browser/animations";
32+
33+
import { AppComponent } from "./app/app.component";
34+
import { environment } from "./environments/environment";
35+
36+
if (environment.production) {
37+
enableProdMode();
38+
}
39+
40+
bootstrapApplication(AppComponent, {
41+
providers: [withAnimations()],
42+
}).catch((err) => console.error(err));
43+
```
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
# Lazy loading a feature using the Angular Router
2+
3+
## Resolving a Routes array
4+
5+
To lazy load an Angular feature, resolve a `Routes` array from the dynamic `import` statement returned by a `loadChildren` callback:
6+
7+
```typescript
8+
import { Routes } from "@angular/router";
9+
10+
import { AboutComponent } from "./app/about.component";
11+
import { HomeComponent } from "./app/home.component";
12+
13+
export const routes: Routes = [
14+
{
15+
path: "",
16+
pathMatch: "full",
17+
redirectTo: "home",
18+
},
19+
{
20+
path: "home",
21+
component: HomeComponent,
22+
},
23+
{
24+
path: "about",
25+
component: AboutComponent,
26+
},
27+
{
28+
path: "category",
29+
loadChildren: () => import("./category/category.routes").then((m) => m.routes),
30+
},
31+
];
32+
```
33+
34+
## Exporting feature routes
35+
36+
Our Angular feature exports a `Routes` array to enable lazy loading using the Angular Router.
37+
38+
```typescript
39+
import { Routes } from "@angular/router";
40+
41+
import { CategoryComponent } from "./category.component";
42+
import { CategoryListComponent } from "./category-list.component";
43+
44+
export const routes: Routes = [
45+
{
46+
path: "",
47+
pathMatch: "full",
48+
component: CategoryListComponent,
49+
},
50+
{
51+
path: ":name",
52+
component: CategoryComponent,
53+
},
54+
];
55+
```
56+
57+
## Lazy loading specific components in a feature
58+
59+
Let's say that we wanted to eagerly load the default component of our feature, in this case the `CategoryListComponent`. Our routes configuration is the same as in the previous section. Now let's say that we wanted to lazy load the `CategoryComponent` used to display individual categories. We do this by adding a `loadComponent` callback to the component route:
60+
61+
```typescript
62+
import { Routes } from "@angular/router";
63+
64+
import { CategoryListComponent } from "./category-list.component";
65+
66+
export const routes: Routes = [
67+
{
68+
path: "",
69+
pathMatch: "full",
70+
component: CategoryListComponent,
71+
},
72+
{
73+
path: ":name",
74+
loadComponent: () => import("./category.component").then((m) => m.CategoryComponent),
75+
},
76+
];
77+
```
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
# Lazy loading a standalone component using the Angular Router
2+
3+
Add a `loadComponent` property to a `Route` object to lazy load a component. The value is a function that returns a dynamic `import` statement that points to an ES module (a `.ts` file), then resolves to the component class:
4+
5+
```typescript
6+
import { Routes } from "@angular/router";
7+
8+
import { HomeComponent } from "./app/home.component";
9+
10+
export const routes: Routes = [
11+
{
12+
path: "",
13+
pathMatch: "full",
14+
redirectTo: "home",
15+
},
16+
{
17+
path: "home",
18+
component: HomeComponent,
19+
},
20+
{
21+
path: "about",
22+
loadComponent: () => import("./about.component").then((m) => m.AboutComponent),
23+
},
24+
];
25+
```
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
# Providing dependencies in a standalone Angular feature
2+
3+
## Using route providers
4+
5+
If all routes in a feature `Routes` array are top-level routes, we can wrap them in a component-less route with an empty path by nesting them in an array assigned to its `children` property.
6+
7+
Next, we add the feature-specific dependencies to the `providers` array of our feature routes:
8+
9+
```typescript
10+
import { Routes } from "@angular/router";
11+
12+
import { CategoryComponent } from "./category.component";
13+
import { CategoryHttpClient } from "./category-http-client.service";
14+
import { CategoryListComponent } from "./category-list.component";
15+
import { CategoryState } from "./category-state.service";
16+
17+
export const routes: Routes = [
18+
{
19+
path: "",
20+
children: [
21+
{
22+
path: "",
23+
pathMatch: "full",
24+
component: CategoryListComponent,
25+
},
26+
{
27+
path: ":name",
28+
component: CategoryComponent,
29+
},
30+
],
31+
providers: [CategoryHttpClient, CategoryState],
32+
},
33+
];
34+
```
35+
36+
## Interoperability with NgModules
37+
38+
Angular libraries using the forRoot-forFeature pattern expose an NgModule that provides dependencies that we must load with the Angular feature using it. To use it in a standalone Angular feature, we pass the NgModule to the `importProvidersFrom` function:
39+
40+
```typescript
41+
import { importProvidersFrom } from "@angular/core";
42+
import { Routes } from "@angular/router";
43+
import { EffectsModule } from "@ngrx/effects";
44+
import { StoreModule } from "@ngrx/store";
45+
46+
import { CategoryEffects } from "./+state/effects";
47+
import { categoryFeature } from "./+state/reducers";
48+
import { CategoryComponent } from "./category.component";
49+
import { CategoryListComponent } from "./category-list.component";
50+
51+
export const routes: Routes = [
52+
{
53+
path: "",
54+
children: [
55+
{
56+
path: "",
57+
pathMatch: "full",
58+
component: CategoryListComponent,
59+
},
60+
{
61+
path: ":name",
62+
component: CategoryComponent,
63+
},
64+
],
65+
providers: [
66+
importProvidersFrom(EffectsModule.forFeature([CategoryEffects])),
67+
importProvidersFrom(StoreModule.forFeature(categoryFeature)),
68+
],
69+
},
70+
];
71+
```

0 commit comments

Comments
 (0)