+ by {{ book.volumeInfo.authors }}
+ Remove from Collection
+
+ }
+ `,
+})
+export class BookCollection {
+ @Input() books: ReadonlyArray = [];
+ @Output() remove = new EventEmitter();
+}
diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/book-list/book-list.component.css b/projects/www/src/app/examples/store-walkthrough/src/book-list/book-list.css
similarity index 98%
rename from projects/www/src/app/examples/store-walkthrough/src/app/book-list/book-list.component.css
rename to projects/www/src/app/examples/store-walkthrough/src/book-list/book-list.css
index 374d31d7be..8b38025829 100644
--- a/projects/www/src/app/examples/store-walkthrough/src/app/book-list/book-list.component.css
+++ b/projects/www/src/app/examples/store-walkthrough/src/book-list/book-list.css
@@ -8,4 +8,4 @@ p {
display: inline-block;
font-style: italic;
margin: 0;
-}
\ No newline at end of file
+}
diff --git a/projects/www/src/app/examples/store-walkthrough/src/book-list/book-list.ts b/projects/www/src/app/examples/store-walkthrough/src/book-list/book-list.ts
new file mode 100644
index 0000000000..851552c172
--- /dev/null
+++ b/projects/www/src/app/examples/store-walkthrough/src/book-list/book-list.ts
@@ -0,0 +1,19 @@
+import { Component, EventEmitter, Input, Output } from '@angular/core';
+import { Book } from './book';
+
+@Component({
+ selector: 'app-book-list',
+ template: `
+ @for (book of books; track book) {
+
+
{{ book.volumeInfo.title }}
+ by {{ book.volumeInfo.authors }}
+ Add to Collection
+
+ }
+ `,
+})
+export class BookList {
+ @Input() books: ReadonlyArray = [];
+ @Output() add = new EventEmitter();
+}
diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/book-list/books.model.ts b/projects/www/src/app/examples/store-walkthrough/src/book-list/book.ts
similarity index 100%
rename from projects/www/src/app/examples/store-walkthrough/src/app/book-list/books.model.ts
rename to projects/www/src/app/examples/store-walkthrough/src/book-list/book.ts
diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/book-list/books.service.ts b/projects/www/src/app/examples/store-walkthrough/src/book-list/books-service.ts
similarity index 66%
rename from projects/www/src/app/examples/store-walkthrough/src/app/book-list/books.service.ts
rename to projects/www/src/app/examples/store-walkthrough/src/book-list/books-service.ts
index 266cc3ab37..d6b5fb8b16 100644
--- a/projects/www/src/app/examples/store-walkthrough/src/app/book-list/books.service.ts
+++ b/projects/www/src/app/examples/store-walkthrough/src/book-list/books-service.ts
@@ -1,13 +1,12 @@
import { HttpClient } from '@angular/common/http';
-import { Injectable } from '@angular/core';
+import { inject, Injectable } from '@angular/core';
-import { Observable } from 'rxjs';
-import { map } from 'rxjs/operators';
-import { Book } from './books.model';
+import { Observable, map } from 'rxjs';
+import { Book } from './book';
@Injectable({ providedIn: 'root' })
export class GoogleBooksService {
- constructor(private http: HttpClient) {}
+ private readonly http = inject(HttpClient);
getBooks(): Observable> {
return this.http
diff --git a/projects/www/src/app/examples/store-walkthrough/src/index.html b/projects/www/src/app/examples/store-walkthrough/src/index.html
deleted file mode 100644
index 371e0a2fb9..0000000000
--- a/projects/www/src/app/examples/store-walkthrough/src/index.html
+++ /dev/null
@@ -1,13 +0,0 @@
-
-
-
-
- NgRx Tutorial
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/projects/www/src/app/examples/store-walkthrough/src/main.ts b/projects/www/src/app/examples/store-walkthrough/src/main.ts
index 2e578fde01..363eedc107 100644
--- a/projects/www/src/app/examples/store-walkthrough/src/main.ts
+++ b/projects/www/src/app/examples/store-walkthrough/src/main.ts
@@ -1,19 +1,6 @@
-import './polyfills';
+import '@angular/compiler';
+import { bootstrapApplication } from '@angular/platform-browser';
+import { App } from './app';
+import { appConfig } from './app.config';
-import { enableProdMode } from '@angular/core';
-import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
-
-import { AppModule } from './app/app.module';
-
-platformBrowserDynamic()
- .bootstrapModule(AppModule)
- .then((ref) => {
- // Ensure Angular destroys itself on hot reloads.
- if (window['ngRef']) {
- window['ngRef'].destroy();
- }
- window['ngRef'] = ref;
-
- // Otherwise, log the boot error
- })
- .catch((err) => console.error(err));
+bootstrapApplication(App, appConfig);
diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/state/app.state.ts b/projects/www/src/app/examples/store-walkthrough/src/state/app.state.ts
similarity index 66%
rename from projects/www/src/app/examples/store-walkthrough/src/app/state/app.state.ts
rename to projects/www/src/app/examples/store-walkthrough/src/state/app.state.ts
index b33494b040..5179f1682d 100644
--- a/projects/www/src/app/examples/store-walkthrough/src/app/state/app.state.ts
+++ b/projects/www/src/app/examples/store-walkthrough/src/state/app.state.ts
@@ -1,4 +1,4 @@
-import { Book } from '../book-list/books.model';
+import { Book } from '../book-list/book';
export interface AppState {
books: ReadonlyArray;
diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/state/books.actions.ts b/projects/www/src/app/examples/store-walkthrough/src/state/books.actions.ts
similarity index 89%
rename from projects/www/src/app/examples/store-walkthrough/src/app/state/books.actions.ts
rename to projects/www/src/app/examples/store-walkthrough/src/state/books.actions.ts
index 3c075ef4f7..b4e63a4195 100644
--- a/projects/www/src/app/examples/store-walkthrough/src/app/state/books.actions.ts
+++ b/projects/www/src/app/examples/store-walkthrough/src/state/books.actions.ts
@@ -1,5 +1,5 @@
import { createActionGroup, props } from '@ngrx/store';
-import { Book } from '../book-list/books.model';
+import { Book } from '../book-list/book';
export const BooksActions = createActionGroup({
source: 'Books',
diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/state/books.reducer.ts b/projects/www/src/app/examples/store-walkthrough/src/state/books.reducer.ts
similarity index 85%
rename from projects/www/src/app/examples/store-walkthrough/src/app/state/books.reducer.ts
rename to projects/www/src/app/examples/store-walkthrough/src/state/books.reducer.ts
index b96101a25a..b961cfa1f4 100644
--- a/projects/www/src/app/examples/store-walkthrough/src/app/state/books.reducer.ts
+++ b/projects/www/src/app/examples/store-walkthrough/src/state/books.reducer.ts
@@ -1,7 +1,7 @@
import { createReducer, on } from '@ngrx/store';
import { BooksApiActions } from './books.actions';
-import { Book } from '../book-list/books.model';
+import { Book } from '../book-list/book';
export const initialState: ReadonlyArray = [];
diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/state/books.selectors.ts b/projects/www/src/app/examples/store-walkthrough/src/state/books.selectors.ts
similarity index 90%
rename from projects/www/src/app/examples/store-walkthrough/src/app/state/books.selectors.ts
rename to projects/www/src/app/examples/store-walkthrough/src/state/books.selectors.ts
index 834850f209..300c30eb63 100644
--- a/projects/www/src/app/examples/store-walkthrough/src/app/state/books.selectors.ts
+++ b/projects/www/src/app/examples/store-walkthrough/src/state/books.selectors.ts
@@ -1,5 +1,5 @@
import { createSelector, createFeatureSelector } from '@ngrx/store';
-import { Book } from '../book-list/books.model';
+import { Book } from '../book-list/book';
export const selectBooks = createFeatureSelector>('books');
diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/state/collection.reducer.ts b/projects/www/src/app/examples/store-walkthrough/src/state/collection.reducer.ts
similarity index 100%
rename from projects/www/src/app/examples/store-walkthrough/src/app/state/collection.reducer.ts
rename to projects/www/src/app/examples/store-walkthrough/src/state/collection.reducer.ts
diff --git a/projects/www/src/app/examples/store-walkthrough/stackblitz.yml b/projects/www/src/app/examples/store-walkthrough/stackblitz.yml
new file mode 100644
index 0000000000..7ca3714e3e
--- /dev/null
+++ b/projects/www/src/app/examples/store-walkthrough/stackblitz.yml
@@ -0,0 +1,20 @@
+name: 'Starter project with NgRx dependencies'
+description: 'A simple Angular project with NgRx dependencies'
+extends: '../__base/stackblitz-empty.yml'
+open: src/app.ts
+files:
+ src/main.ts: './src/main.ts'
+ src/app.ts: './src/app.ts'
+ src/app.config.ts: './src/app.config.ts'
+ src/state/app.state.ts: './src/state/app.state.ts'
+ src/state/books.actions.ts: './src/state/books.actions.ts'
+ src/state/books.reducer.ts: './src/state/books.reducer.ts'
+ src/state/books.selectors.ts: './src/state/books.selectors.ts'
+ src/state/collection.reducer.ts: './src/state/collection.reducer.ts'
+ src/book-list/book-list.ts: './src/book-list/book-list.ts'
+ src/book-list/book-list.css: './src/book-list/book-list.css'
+ src/book-list/book.ts: './src/book-list/book.ts'
+ src/book-list/books-service.ts: './src/book-list/books-service.ts'
+ src/book-collection/book-collection.ts: './src/book-collection/book-collection.ts'
+ src/book-collection/book-collection.css: './src/book-collection/book-collection.css'
+ index.html: './index.html'
diff --git a/projects/www/src/app/examples/testing-store/src/app/app.component.html b/projects/www/src/app/examples/testing-store/src/app/app.component.html
index 7bf6a9555f..b991dbb1ab 100644
--- a/projects/www/src/app/examples/testing-store/src/app/app.component.html
+++ b/projects/www/src/app/examples/testing-store/src/app/app.component.html
@@ -4,13 +4,12 @@
Books
My Collection
-
diff --git a/projects/www/src/app/examples/testing-store/src/app/book-collection/book-collection.component.css b/projects/www/src/app/examples/testing-store/src/app/book-collection/book-collection.component.css
index 24469d9a62..fe3e6691ae 100644
--- a/projects/www/src/app/examples/testing-store/src/app/book-collection/book-collection.component.css
+++ b/projects/www/src/app/examples/testing-store/src/app/book-collection/book-collection.component.css
@@ -8,4 +8,4 @@ p {
display: inline-block;
font-style: italic;
margin: 0 0 5px;
-}
\ No newline at end of file
+}
diff --git a/projects/www/src/app/examples/testing-store/src/app/book-collection/book-collection.component.html b/projects/www/src/app/examples/testing-store/src/app/book-collection/book-collection.component.html
index 2a65f9ecc0..af8fa2595a 100644
--- a/projects/www/src/app/examples/testing-store/src/app/book-collection/book-collection.component.html
+++ b/projects/www/src/app/examples/testing-store/src/app/book-collection/book-collection.component.html
@@ -1,10 +1,7 @@
-
-
{{book.volumeInfo.title}}
by {{book.volumeInfo.authors}}
- Remove from Collection
+
+
{{ book.volumeInfo.title }}
+ by {{ book.volumeInfo.authors }}
+
+ Remove from Collection
+
diff --git a/projects/www/src/app/examples/testing-store/src/app/book-list/book-list.component.css b/projects/www/src/app/examples/testing-store/src/app/book-list/book-list.component.css
index 374d31d7be..8b38025829 100644
--- a/projects/www/src/app/examples/testing-store/src/app/book-list/book-list.component.css
+++ b/projects/www/src/app/examples/testing-store/src/app/book-list/book-list.component.css
@@ -8,4 +8,4 @@ p {
display: inline-block;
font-style: italic;
margin: 0;
-}
\ No newline at end of file
+}
diff --git a/projects/www/src/app/examples/testing-store/src/app/book-list/book-list.component.html b/projects/www/src/app/examples/testing-store/src/app/book-list/book-list.component.html
index b3fb0e12b0..8ef9f7780b 100644
--- a/projects/www/src/app/examples/testing-store/src/app/book-list/book-list.component.html
+++ b/projects/www/src/app/examples/testing-store/src/app/book-list/book-list.component.html
@@ -1,10 +1,7 @@
-
-
{{book.volumeInfo.title}}
by {{book.volumeInfo.authors}}
- Add to Collection
-
\ No newline at end of file
+
+
{{ book.volumeInfo.title }}
+ by {{ book.volumeInfo.authors }}
+
+ Add to Collection
+
+
diff --git a/projects/www/src/app/examples/testing-store/src/index.html b/projects/www/src/app/examples/testing-store/src/index.html
index f902fba22d..f8da00869e 100644
--- a/projects/www/src/app/examples/testing-store/src/index.html
+++ b/projects/www/src/app/examples/testing-store/src/index.html
@@ -1,4 +1,4 @@
-
+
diff --git a/projects/www/src/app/pages/guide/data/architecture-overview.md b/projects/www/src/app/pages/guide/data/architecture-overview.md
index 954572e6f3..af571b7f4a 100644
--- a/projects/www/src/app/pages/guide/data/architecture-overview.md
+++ b/projects/www/src/app/pages/guide/data/architecture-overview.md
@@ -24,7 +24,6 @@ such as `QUERY_ALL` for the `Hero` entity type.
1. The view/component calls [`EntityCollectionService.getAll()`](guide/data/entity-services), which dispatches the hero's `QUERY_ALL` [EntityAction](guide/data/entity-actions) to the store.
2. NgRx kicks into gear ...
-
1. The NgRx Data [EntityReducer](guide/data/entity-reducer) reads the action's `entityName` property (`Hero` in this example) and
forwards the action and existing entity collection state to the `EntityCollectionReducer` for heroes.
diff --git a/projects/www/src/app/pages/guide/data/entity-metadata.md b/projects/www/src/app/pages/guide/data/entity-metadata.md
index 73f8fdb118..119ce5f9b4 100644
--- a/projects/www/src/app/pages/guide/data/entity-metadata.md
+++ b/projects/www/src/app/pages/guide/data/entity-metadata.md
@@ -155,7 +155,7 @@ export function nameAndSayingFilter(
entities: Villain[],
pattern: string
) {
- return PropsFilterFnFactory[('name', 'saying')](
+ return (PropsFilterFnFactory)[('name', 'saying')](
entities,
pattern
);
@@ -276,7 +276,7 @@ Following the prior step, we have added the additional property to the `action.p
```typescript
export class AdditionalEntityCollectionReducerMethods<
- T
+ T,
> extends EntityCollectionReducerMethods {
constructor(
public entityName: string,
diff --git a/projects/www/src/app/pages/guide/signals/signal-state.md b/projects/www/src/app/pages/guide/signals/signal-state.md
index 2b276de532..5bd49cb35e 100644
--- a/projects/www/src/app/pages/guide/signals/signal-state.md
+++ b/projects/www/src/app/pages/guide/signals/signal-state.md
@@ -227,13 +227,13 @@ import { BookListStore } from './book-list-store';
@for (movie of store.movies(); track movie.id) {
-
{{ movie.id }}: {{ movie.name }}
+
{{ movie.id }}: {{ movie.name }}
}
`,
diff --git a/projects/www/src/app/pages/guide/store/configuration/runtime-checks.md b/projects/www/src/app/pages/guide/store/configuration/runtime-checks.md
index a20a4f09c9..afb4fe4c21 100644
--- a/projects/www/src/app/pages/guide/store/configuration/runtime-checks.md
+++ b/projects/www/src/app/pages/guide/store/configuration/runtime-checks.md
@@ -58,9 +58,9 @@ export const reducer = createReducer(
initialState,
on(addTodo, (state, { todo }) => {
// Violation 1: we assign a new value to `todoInput` directly
- (state.todoInput = ''),
+ ((state.todoInput = ''),
// Violation 2: `push` modifies the array
- state.todos.push(todo);
+ state.todos.push(todo));
})
);
```
diff --git a/projects/www/src/app/pages/guide/store/selectors.md b/projects/www/src/app/pages/guide/store/selectors.md
index c4168242f0..6abfbda9a1 100644
--- a/projects/www/src/app/pages/guide/store/selectors.md
+++ b/projects/www/src/app/pages/guide/store/selectors.md
@@ -493,11 +493,14 @@ export const selectLastStateTransitions = (count: number) => {
return pipe(
// Thanks to `createSelector` the operator will have memoization "for free"
select(selectProjectedValues), // Combines the last `count` state values in array
- scan((acc, curr) => {
- return [curr, ...acc].filter(
- (val, index) => index < count && val !== undefined
- );
- }, [] as { foo: number; bar: string }[]) // XX: Explicit type hint for the array.
+ scan(
+ (acc, curr) => {
+ return [curr, ...acc].filter(
+ (val, index) => index < count && val !== undefined
+ );
+ },
+ [] as { foo: number; bar: string }[]
+ ) // XX: Explicit type hint for the array.
// Equivalent to what is emitted by the selector
);
};
diff --git a/projects/www/src/app/pages/guide/store/walkthrough.md b/projects/www/src/app/pages/guide/store/walkthrough.md
index 8b027695f4..2918958b13 100644
--- a/projects/www/src/app/pages/guide/store/walkthrough.md
+++ b/projects/www/src/app/pages/guide/store/walkthrough.md
@@ -1,91 +1,71 @@
# Walkthrough
-The following example more extensively utilizes the key concepts of store to manage the state of book list, and how the user can add a book to and remove it from their collection within an Angular component. Try the .
+The following example more extensively utilizes the key concepts of store to manage the state of book list, and how the user can add a book to and remove it from their collection within an Angular component. To build the example, follow the steps in the tutorial below.
-## Tutorial
-
-1. Generate a new project using StackBlitz and create a folder named `book-list` inside the `app` folder. This folder is used to hold the book list component later in the tutorial. For now, let's start with adding a file named `books.model.ts` to reference different aspects of a book in the book list.
-
-
-
-
-
-2. Right click on the `app` folder to create a state management folder `state`. Within the new folder, create a new file `books.actions.ts` to describe the book actions. Book actions include the book list retrieval, and the add and remove book actions.
+The full example is available on StackBlitz:
-
-
-
-
-3. Right click on the `state` folder and create a new file labeled `books.reducer.ts`. Within this file, define a reducer function to handle the retrieval of the book list from the state and consequently, update the state.
-
-
-
-
+
-4. Create another file named `collection.reducer.ts` in the `state` folder to handle actions that alter the user's book collection. Define a reducer function that handles the add action by appending the book's ID to the collection, including a condition to avoid duplicate book IDs. Define the same reducer to handle the remove action by filtering the collection array with the book ID.
+## Tutorial
-
+1. Generate a new project using the and create a folder named `book-list` inside the `src` folder. This folder is used to hold the book list component later in the tutorial. For now, let's start with adding a file named `book.ts` to reference different aspects of a book in the book list.
+
-5. Import the `StoreModule` from `@ngrx/store` and the `books.reducer` and `collection.reducer` file.
-
-
+1. Right click on the `app` folder to create a state management folder `state`. Within the new folder, create a new file `books.actions.ts` to describe the book actions. Book actions include the book list retrieval, and the add and remove book actions.
+
-6. Add the `StoreModule.forRoot` function in the `imports` array of your `AppModule` with an object containing the `books` and `booksReducer`, as well as the `collection` and `collectionReducer` that manage the state of the book list and the collection. The `StoreModule.forRoot()` method registers the global providers needed to access the `Store` throughout your application.
-
-
+3. Right click on the `state` folder and create a new file labeled `books.reducer.ts`. Within this file, define a reducer function to handle the retrieval of the book list from the state and consequently, update the state.
+
-7. Create the book list and collection selectors to ensure we get the correct information from the store. As you can see, the `selectBookCollection` selector combines two other selectors in order to build its return value.
-
-
+4. Create another file named `collection.reducer.ts` in the `state` folder to handle actions that alter the user's book collection. Define a reducer function that handles the add action by appending the book's ID to the collection, including a condition to avoid duplicate book IDs. Define the same reducer to handle the remove action by filtering the collection array with the book ID.
+
-8. In the `book-list` folder, we want to have a service that fetches the data needed for the book list from an API. Create a file in the `book-list` folder named `books.service.ts`, which will call the Google Books API and return a list of books.
-
-
+5. Add the `provideStore` function in the `providers` array of your `app.config.ts` with an object containing the `books` and `booksReducer`, as well as the `collection` and `collectionReducer` that manage the state of the book list and the collection. The `provideStore` function registers the global providers needed to access the `Store` throughout your application.
+
-9. In the same folder (`book-list`), create the `BookListComponent` with the following template. Update the `BookListComponent` class to dispatch the `add` event.
-
-
+6. Create the book list and collection selectors to ensure we get the correct information from the store. As you can see, the `selectBookCollection` selector combines two other selectors in order to build its return value.
+
-
+7. In the `book-list` folder, we want to have a service that fetches the data needed for the book list from an API. Create a file in the `book-list` folder named `books.service.ts`, which will call the Google Books API and return a list of books.
+
-10. Create a new _Component_ named `book-collection` in the `app` folder. Update the `BookCollectionComponent` template and class.
-
-
+8. Add the `HttpClient` module using the `provideHttpClient` provider in the `app.config.ts` file in order to make HTTP requests using the `HttpClient`.
+
-
+9. In the same folder (`book-list`), create the `BookList` with the following template. Update the `BookList` class to dispatch the `add` event.
+
-11. Add `BookListComponent` and `BookCollectionComponent` to your `AppComponent` template, and to your declarations (along with their top level import statements) in `app.module.ts` as well.
-
-
+10. Create a new _Component_ named `book-collection` in the `app` folder. Update the `BookCollection` template and class.
+
-
+11. Add `BookList` and `BookCollection` to your `App` template, and to your imports in `app.ts` as well.
+
-12. In the `AppComponent` class, add the selectors and corresponding actions to dispatch on `add` or `remove` method calls. Then subscribe to the Google Books API in order to update the state. (This should probably be handled by NgRx Effects, which you can read about [here](guide/effects). For the sake of this demo, NgRx Effects is not being included).
-
-
+12. In the `App` class, add the selectors and corresponding actions to dispatch on `add` or `remove` method calls. Then subscribe to the Google Books API in order to update the state. (This should probably be handled by NgRx Effects, which you can read about [here](guide/effects). For the sake of this demo, NgRx Effects is not being included).
+
And that's it! Click the add and remove buttons to change the state.
diff --git a/projects/www/src/styles.scss b/projects/www/src/styles.scss
index db514f005f..667f854e37 100644
--- a/projects/www/src/styles.scss
+++ b/projects/www/src/styles.scss
@@ -10,11 +10,13 @@ html {
-moz-text-size-adjust: none;
-webkit-text-size-adjust: none;
text-size-adjust: none;
- @include mat.theme((
- color: mat.$violet-palette,
- typography: Roboto,
- density: 0
- ));
+ @include mat.theme(
+ (
+ color: mat.$violet-palette,
+ typography: Roboto,
+ density: 0,
+ )
+ );
}
*,
@@ -112,7 +114,7 @@ code {
a {
text-decoration: none;
color: #fface6;
- cursor: pointer
+ cursor: pointer;
}
// Set up Angular Material