From 3bf9a4986548681af9726bfc98d863eb2c12ad96 Mon Sep 17 00:00:00 2001 From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com> Date: Tue, 9 Sep 2025 15:39:37 +0200 Subject: [PATCH 1/3] docs(www): update walkthrough --- .../app/examples/__base/stackblitz-empty.yml | 8 + .../src/app/examples/ngrx-start/index.html | 14 ++ .../src/{app.component.ts => app.ts} | 4 +- .../src/app/examples/ngrx-start/src/main.ts | 14 ++ .../app/examples/ngrx-start/stackblitz.yml | 7 +- .../app/examples/store-walkthrough/index.html | 14 ++ .../store-walkthrough/src/app.config.ts | 14 ++ .../app/examples/store-walkthrough/src/app.ts | 48 ++++++ .../src/app/app.component.html | 10 -- .../src/app/app.component.spec.ts | 160 ------------------ .../src/app/app.component.ts | 36 ---- .../store-walkthrough/src/app/app.module.1.ts | 20 --- .../store-walkthrough/src/app/app.module.ts | 22 --- .../book-collection.component.html | 10 -- .../book-collection.component.ts | 12 -- .../app/book-list/book-list.component.html | 10 -- .../src/app/book-list/book-list.component.ts | 12 -- .../src/app/tests/app.component.1.spec.ts | 147 ---------------- .../src/app/tests/integration.spec.ts | 122 ------------- .../book-collection.css} | 2 +- .../src/book-collection/book-collection.ts | 21 +++ .../book-list.css} | 0 .../src/book-list/book-list.ts | 21 +++ .../src/{app => }/book-list/books.model.ts | 0 .../books.service.ts => book-list/books.ts} | 9 +- .../examples/store-walkthrough/src/index.html | 13 -- .../examples/store-walkthrough/src/main.ts | 34 ++-- .../src/{app => }/state/app.state.ts | 0 .../src/{app => }/state/books.actions.ts | 0 .../src/{app => }/state/books.reducer.ts | 0 .../src/{app => }/state/books.selectors.ts | 0 .../src/{app => }/state/collection.reducer.ts | 0 .../examples/store-walkthrough/stackblitz.yml | 20 +++ .../src/app/pages/guide/store/walkthrough.md | 76 +++------ 34 files changed, 229 insertions(+), 651 deletions(-) create mode 100644 projects/www/src/app/examples/__base/stackblitz-empty.yml create mode 100644 projects/www/src/app/examples/ngrx-start/index.html rename projects/www/src/app/examples/ngrx-start/src/{app.component.ts => app.ts} (64%) create mode 100644 projects/www/src/app/examples/ngrx-start/src/main.ts create mode 100644 projects/www/src/app/examples/store-walkthrough/index.html create mode 100644 projects/www/src/app/examples/store-walkthrough/src/app.config.ts create mode 100644 projects/www/src/app/examples/store-walkthrough/src/app.ts delete mode 100644 projects/www/src/app/examples/store-walkthrough/src/app/app.component.html delete mode 100644 projects/www/src/app/examples/store-walkthrough/src/app/app.component.spec.ts delete mode 100644 projects/www/src/app/examples/store-walkthrough/src/app/app.component.ts delete mode 100644 projects/www/src/app/examples/store-walkthrough/src/app/app.module.1.ts delete mode 100644 projects/www/src/app/examples/store-walkthrough/src/app/app.module.ts delete mode 100644 projects/www/src/app/examples/store-walkthrough/src/app/book-collection/book-collection.component.html delete mode 100644 projects/www/src/app/examples/store-walkthrough/src/app/book-collection/book-collection.component.ts delete mode 100644 projects/www/src/app/examples/store-walkthrough/src/app/book-list/book-list.component.html delete mode 100644 projects/www/src/app/examples/store-walkthrough/src/app/book-list/book-list.component.ts delete mode 100644 projects/www/src/app/examples/store-walkthrough/src/app/tests/app.component.1.spec.ts delete mode 100644 projects/www/src/app/examples/store-walkthrough/src/app/tests/integration.spec.ts rename projects/www/src/app/examples/store-walkthrough/src/{app/book-collection/book-collection.component.css => book-collection/book-collection.css} (98%) create mode 100644 projects/www/src/app/examples/store-walkthrough/src/book-collection/book-collection.ts rename projects/www/src/app/examples/store-walkthrough/src/{app/book-list/book-list.component.css => book-list/book-list.css} (100%) create mode 100644 projects/www/src/app/examples/store-walkthrough/src/book-list/book-list.ts rename projects/www/src/app/examples/store-walkthrough/src/{app => }/book-list/books.model.ts (100%) rename projects/www/src/app/examples/store-walkthrough/src/{app/book-list/books.service.ts => book-list/books.ts} (67%) delete mode 100644 projects/www/src/app/examples/store-walkthrough/src/index.html rename projects/www/src/app/examples/store-walkthrough/src/{app => }/state/app.state.ts (100%) rename projects/www/src/app/examples/store-walkthrough/src/{app => }/state/books.actions.ts (100%) rename projects/www/src/app/examples/store-walkthrough/src/{app => }/state/books.reducer.ts (100%) rename projects/www/src/app/examples/store-walkthrough/src/{app => }/state/books.selectors.ts (100%) rename projects/www/src/app/examples/store-walkthrough/src/{app => }/state/collection.reducer.ts (100%) create mode 100644 projects/www/src/app/examples/store-walkthrough/stackblitz.yml diff --git a/projects/www/src/app/examples/__base/stackblitz-empty.yml b/projects/www/src/app/examples/__base/stackblitz-empty.yml new file mode 100644 index 0000000000..a348394a74 --- /dev/null +++ b/projects/www/src/app/examples/__base/stackblitz-empty.yml @@ -0,0 +1,8 @@ +name: Base withouth main and app files +description: Base template for NgRx examples +files: + src/_theme.scss: './src/_theme.scss' + src/styles.scss: './src/styles.scss' + package.json: './package.json' + tsconfig.json: './tsconfig.json' + vite.config.js: './vite.config.js' diff --git a/projects/www/src/app/examples/ngrx-start/index.html b/projects/www/src/app/examples/ngrx-start/index.html new file mode 100644 index 0000000000..17d565af7f --- /dev/null +++ b/projects/www/src/app/examples/ngrx-start/index.html @@ -0,0 +1,14 @@ + + + + + NgRx Example + + + + + + Loading... + + + diff --git a/projects/www/src/app/examples/ngrx-start/src/app.component.ts b/projects/www/src/app/examples/ngrx-start/src/app.ts similarity index 64% rename from projects/www/src/app/examples/ngrx-start/src/app.component.ts rename to projects/www/src/app/examples/ngrx-start/src/app.ts index 9c1ddc23d8..c62b3832e5 100644 --- a/projects/www/src/app/examples/ngrx-start/src/app.component.ts +++ b/projects/www/src/app/examples/ngrx-start/src/app.ts @@ -1,7 +1,7 @@ import { Component } from '@angular/core'; @Component({ - selector: 'ngrx-root', + selector: 'app-root', template: `

NgRx base

`, }) -export class AppComponent {} +export class App {} diff --git a/projects/www/src/app/examples/ngrx-start/src/main.ts b/projects/www/src/app/examples/ngrx-start/src/main.ts new file mode 100644 index 0000000000..df19f9c747 --- /dev/null +++ b/projects/www/src/app/examples/ngrx-start/src/main.ts @@ -0,0 +1,14 @@ +import '@angular/compiler'; +import { bootstrapApplication } from '@angular/platform-browser'; +import { + mergeApplicationConfig, + provideZonelessChangeDetection, +} from '@angular/core'; +import { App } from './app'; +import { appConfig } from './app.config'; + +const config = mergeApplicationConfig(appConfig, { + providers: [provideZonelessChangeDetection()], +}); + +bootstrapApplication(App, config); diff --git a/projects/www/src/app/examples/ngrx-start/stackblitz.yml b/projects/www/src/app/examples/ngrx-start/stackblitz.yml index c38fced9b5..fee6871807 100644 --- a/projects/www/src/app/examples/ngrx-start/stackblitz.yml +++ b/projects/www/src/app/examples/ngrx-start/stackblitz.yml @@ -1,6 +1,9 @@ name: 'Starter project with NgRx dependencies' description: 'A simple Angular project with NgRx dependencies' -extends: '../__base/stackblitz.yml' +extends: '../__base/stackblitz-empty.yml' +open: src/app.ts files: - src/app.component.ts: './src/app.component.ts' + src/main.ts: './src/main.ts' + src/app.ts: './src/app.ts' src/app.config.ts: './src/app.config.ts' + index.html: './index.html' diff --git a/projects/www/src/app/examples/store-walkthrough/index.html b/projects/www/src/app/examples/store-walkthrough/index.html new file mode 100644 index 0000000000..17d565af7f --- /dev/null +++ b/projects/www/src/app/examples/store-walkthrough/index.html @@ -0,0 +1,14 @@ + + + + + NgRx Example + + + + + + Loading... + + + diff --git a/projects/www/src/app/examples/store-walkthrough/src/app.config.ts b/projects/www/src/app/examples/store-walkthrough/src/app.config.ts new file mode 100644 index 0000000000..4809ebc21f --- /dev/null +++ b/projects/www/src/app/examples/store-walkthrough/src/app.config.ts @@ -0,0 +1,14 @@ +import { ApplicationConfig } from '@angular/core'; +import { provideStore } from '@ngrx/store'; + +import { booksReducer } from './state/books.reducer'; +import { collectionReducer } from './state/collection.reducer'; + +export const appConfig: ApplicationConfig = { + providers: [ + provideStore({ + books: booksReducer, + collection: collectionReducer, + }), + ], +}; diff --git a/projects/www/src/app/examples/store-walkthrough/src/app.ts b/projects/www/src/app/examples/store-walkthrough/src/app.ts new file mode 100644 index 0000000000..ae2d8b62a2 --- /dev/null +++ b/projects/www/src/app/examples/store-walkthrough/src/app.ts @@ -0,0 +1,48 @@ +import { Component, inject, OnInit } from '@angular/core'; +import { Store } from '@ngrx/store'; + +import { selectBookCollection, selectBooks } from './state/books.selectors'; +import { BooksActions, BooksApiActions } from './state/books.actions'; +import { GoogleBooks } from './book-list/books'; +import { BookList } from './book-list/book-list'; +import { BookCollection } from './book-collection/book-collection'; + +@Component({ + selector: 'app-root', + template: ` +

Oliver Sacks Books Collection

+ +

Books

+ + +

My Collection

+ + `, + imports: [BookList, BookCollection], +}) +export class App implements OnInit { + private readonly booksService = inject(GoogleBooks); + private readonly store = inject(Store); + + protected books = this.store.selectSignal(selectBooks); + protected bookCollection = this.store.selectSignal(selectBookCollection); + + protected onAdd(bookId: string) { + this.store.dispatch(BooksActions.addBook({ bookId })); + } + + protected onRemove(bookId: string) { + this.store.dispatch(BooksActions.removeBook({ bookId })); + } + + ngOnInit() { + this.booksService + .getBooks() + .subscribe((books) => + this.store.dispatch(BooksApiActions.retrievedBookList({ books })) + ); + } +} diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/app.component.html b/projects/www/src/app/examples/store-walkthrough/src/app/app.component.html deleted file mode 100644 index ba9276272a..0000000000 --- a/projects/www/src/app/examples/store-walkthrough/src/app/app.component.html +++ /dev/null @@ -1,10 +0,0 @@ -

Oliver Sacks Books Collection

- - -

Books

- - -

My Collection

- - - diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/app.component.spec.ts b/projects/www/src/app/examples/store-walkthrough/src/app/app.component.spec.ts deleted file mode 100644 index 4610454a0f..0000000000 --- a/projects/www/src/app/examples/store-walkthrough/src/app/app.component.spec.ts +++ /dev/null @@ -1,160 +0,0 @@ -import { MemoizedSelector } from '@ngrx/store'; -import { provideMockStore, MockStore } from '@ngrx/store/testing'; -import { TestBed, ComponentFixture } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; - -import { AppState } from './state/app.state'; -import { AppComponent } from './app.component'; -import { addBook, removeBook, retrievedBookList } from './state/books.actions'; -import { BookListComponent } from './book-list/book-list.component'; -import { BookCollectionComponent } from './book-collection/book-collection.component'; -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { By } from '@angular/platform-browser'; -import { - selectBooks, - selectCollectionIds, - selectBookCollection, -} from './state/books.selectors'; - -describe('AppComponent', () => { - let fixture: ComponentFixture; - let component: AppComponent; - let store: MockStore; - let mockBookCollectionSelector; - let mockBooksSelector; - - beforeEach(() => { - TestBed.configureTestingModule({ - providers: [provideMockStore()], - imports: [HttpClientTestingModule], - declarations: [BookListComponent, BookCollectionComponent, AppComponent], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }); - - store = TestBed.inject(MockStore); - fixture = TestBed.createComponent(AppComponent); - component = fixture.componentInstance; - - mockBooksSelector = store.overrideSelector(selectBooks, [ - { - id: 'firstId', - volumeInfo: { - title: 'First Title', - authors: ['First Author'], - }, - }, - { - id: 'secondId', - volumeInfo: { - title: 'Second Title', - authors: ['Second Author'], - }, - }, - { - id: 'thirdId', - volumeInfo: { - title: 'Third Title', - authors: ['Third Author'], - }, - }, - { - id: 'fourthId', - volumeInfo: { - title: 'Fourth Title', - authors: ['Fourth Author'], - }, - }, - ]); - - mockBookCollectionSelector = store.overrideSelector(selectBookCollection, [ - { - id: 'thirdId', - volumeInfo: { - title: 'Third Title', - authors: ['Third Author'], - }, - }, - ]); - - fixture.detectChanges(); - - spyOn(store, 'dispatch').and.callFake(() => {}); - }); - - it('add method should dispatch add action', () => { - component.onAdd('firstId'); - expect(store.dispatch).toHaveBeenCalledWith(addBook({ bookId: 'firstId' })); - }); - - it('remove method should dispatch remove action', () => { - component.onRemove('thirdId'); - expect(store.dispatch).toHaveBeenCalledWith( - removeBook({ bookId: 'thirdId' }) - ); - }); - - it('should render a book list and a book collection', () => { - expect( - fixture.debugElement.queryAll(By.css('.book-list .book-item')).length - ).toBe(4); - expect( - fixture.debugElement.queryAll(By.css('.book-collection .book-item')) - .length - ).toBe(1); - }); - - it('should update the UI when the store changes', () => { - mockBooksSelector.setResult([ - { - id: 'stringA', - volumeInfo: { - title: 'Title A', - authors: ['Author A'], - }, - }, - { - id: 'stringB', - volumeInfo: { - title: 'Title B', - authors: ['Author B'], - }, - }, - { - id: 'stringC', - volumeInfo: { - title: 'Title C', - authors: ['Author C'], - }, - }, - ]); - - mockBookCollectionSelector.setResult([ - { - id: 'stringA', - volumeInfo: { - title: 'Title A', - authors: ['Author A'], - }, - }, - { - id: 'stringB', - volumeInfo: { - title: 'Title B', - authors: ['Author B'], - }, - }, - ]); - - store.refreshState(); - fixture.detectChanges(); - - expect( - fixture.debugElement.queryAll(By.css('.book-list .book-item')).length - ).toBe(3); - - expect( - fixture.debugElement.queryAll(By.css('.book-collection .book-item')) - .length - ).toBe(2); - }); -}); diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/app.component.ts b/projects/www/src/app/examples/store-walkthrough/src/app/app.component.ts deleted file mode 100644 index 3b5d677553..0000000000 --- a/projects/www/src/app/examples/store-walkthrough/src/app/app.component.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { Store } from '@ngrx/store'; - -import { selectBookCollection, selectBooks } from './state/books.selectors'; -import { BooksActions, BooksApiActions } from './state/books.actions'; -import { GoogleBooksService } from './book-list/books.service'; - -@Component({ - selector: 'app-root', - templateUrl: './app.component.html', -}) -export class AppComponent implements OnInit { - books$ = this.store.select(selectBooks); - bookCollection$ = this.store.select(selectBookCollection); - - onAdd(bookId: string) { - this.store.dispatch(BooksActions.addBook({ bookId })); - } - - onRemove(bookId: string) { - this.store.dispatch(BooksActions.removeBook({ bookId })); - } - - constructor( - private booksService: GoogleBooksService, - private store: Store - ) {} - - ngOnInit() { - this.booksService - .getBooks() - .subscribe((books) => - this.store.dispatch(BooksApiActions.retrievedBookList({ books })) - ); - } -} diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/app.module.1.ts b/projects/www/src/app/examples/store-walkthrough/src/app/app.module.1.ts deleted file mode 100644 index ec0a7a2e51..0000000000 --- a/projects/www/src/app/examples/store-walkthrough/src/app/app.module.1.ts +++ /dev/null @@ -1,20 +0,0 @@ -// #docregion partialTopLevelImports -import { HttpClientModule } from '@angular/common/http'; -import { booksReducer } from './state/books.reducer'; -import { collectionReducer } from './state/collection.reducer'; -import { StoreModule } from '@ngrx/store'; -// #enddocregion partialTopLevelImports - -// #docregion storeModuleAddToImports -@NgModule({ - imports: [ - BrowserModule, - StoreModule.forRoot({ books: booksReducer, collection: collectionReducer }), - HttpClientModule, - ], - declarations: [AppComponent], - bootstrap: [AppComponent], -}) -export class AppModule {} - -// #enddocregion storeModuleAddToImports diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/app.module.ts b/projects/www/src/app/examples/store-walkthrough/src/app/app.module.ts deleted file mode 100644 index 87666e90ee..0000000000 --- a/projects/www/src/app/examples/store-walkthrough/src/app/app.module.ts +++ /dev/null @@ -1,22 +0,0 @@ -import { NgModule } from '@angular/core'; -import { BrowserModule } from '@angular/platform-browser'; - -import { HttpClientModule } from '@angular/common/http'; -import { booksReducer } from './state/books.reducer'; -import { collectionReducer } from './state/collection.reducer'; -import { StoreModule } from '@ngrx/store'; - -import { AppComponent } from './app.component'; -import { BookListComponent } from './book-list/book-list.component'; -import { BookCollectionComponent } from './book-collection/book-collection.component'; - -@NgModule({ - imports: [ - BrowserModule, - StoreModule.forRoot({ books: booksReducer, collection: collectionReducer }), - HttpClientModule, - ], - declarations: [AppComponent, BookListComponent, BookCollectionComponent], - bootstrap: [AppComponent], -}) -export class AppModule {} diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/book-collection/book-collection.component.html b/projects/www/src/app/examples/store-walkthrough/src/app/book-collection/book-collection.component.html deleted file mode 100644 index 2a65f9ecc0..0000000000 --- a/projects/www/src/app/examples/store-walkthrough/src/app/book-collection/book-collection.component.html +++ /dev/null @@ -1,10 +0,0 @@ -
-

{{book.volumeInfo.title}}

by {{book.volumeInfo.authors}} - -
diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/book-collection/book-collection.component.ts b/projects/www/src/app/examples/store-walkthrough/src/app/book-collection/book-collection.component.ts deleted file mode 100644 index 346e94f169..0000000000 --- a/projects/www/src/app/examples/store-walkthrough/src/app/book-collection/book-collection.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Book } from '../book-list/books.model'; - -@Component({ - selector: 'app-book-collection', - templateUrl: './book-collection.component.html', - styleUrls: ['./book-collection.component.css'], -}) -export class BookCollectionComponent { - @Input() books: ReadonlyArray = []; - @Output() remove = new EventEmitter(); -} diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/book-list/book-list.component.html b/projects/www/src/app/examples/store-walkthrough/src/app/book-list/book-list.component.html deleted file mode 100644 index b3fb0e12b0..0000000000 --- a/projects/www/src/app/examples/store-walkthrough/src/app/book-list/book-list.component.html +++ /dev/null @@ -1,10 +0,0 @@ -
-

{{book.volumeInfo.title}}

by {{book.volumeInfo.authors}} - -
\ No newline at end of file diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/book-list/book-list.component.ts b/projects/www/src/app/examples/store-walkthrough/src/app/book-list/book-list.component.ts deleted file mode 100644 index c7a53100ea..0000000000 --- a/projects/www/src/app/examples/store-walkthrough/src/app/book-list/book-list.component.ts +++ /dev/null @@ -1,12 +0,0 @@ -import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Book } from './books.model'; - -@Component({ - selector: 'app-book-list', - templateUrl: './book-list.component.html', - styleUrls: ['./book-list.component.css'], -}) -export class BookListComponent { - @Input() books: ReadonlyArray = []; - @Output() add = new EventEmitter(); -} diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/tests/app.component.1.spec.ts b/projects/www/src/app/examples/store-walkthrough/src/app/tests/app.component.1.spec.ts deleted file mode 100644 index c54b82b2f1..0000000000 --- a/projects/www/src/app/examples/store-walkthrough/src/app/tests/app.component.1.spec.ts +++ /dev/null @@ -1,147 +0,0 @@ -import { MemoizedSelector } from '@ngrx/store'; -import { Store, StoreModule } from '@ngrx/store'; -import { provideMockStore, MockStore } from '@ngrx/store/testing'; -import { TestBed, ComponentFixture } from '@angular/core/testing'; -import { HttpClientTestingModule } from '@angular/common/http/testing'; - -import { AppState } from '../state/app.state'; -import { AppComponent } from '../app.component'; -import { - addBook as addAction, - removeBook as removeAction, - retrievedBookList, -} from '../state/books.actions'; -import { BookListComponent } from '../book-list/book-list.component'; -import { BookCollectionComponent } from '../book-collection/book-collection.component'; -import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core'; -import { By } from '@angular/platform-browser'; -import { - selectBooks, - selectCollectionIds, - selectBookCollection, -} from '../state/books.selectors'; - -describe('AppComponent', () => { - let fixture: ComponentFixture; - let component: AppComponent; - let store: MockStore; - let mockBookCollectionSelector; - let mockBooksSelector; - - TestBed.configureTestingModule({ - providers: [provideMockStore()], - imports: [HttpClientTestingModule], - declarations: [BookListComponent, BookCollectionComponent, AppComponent], - schemas: [CUSTOM_ELEMENTS_SCHEMA], - }); - - store = TestBed.inject(MockStore); - fixture = TestBed.createComponent(AppComponent); - component = fixture.componentInstance; - - //#docregion mockSelector - mockBooksSelector = store.overrideSelector(selectBooks, [ - { - id: 'firstId', - volumeInfo: { - title: 'First Title', - authors: ['First Author'], - }, - }, - ]); - - mockBookCollectionSelector = store.overrideSelector(selectBookCollection, []); - - fixture.detectChanges(); - spyOn(store, 'dispatch').and.callFake(() => {}); - - it('should update the UI when the store changes', () => { - mockBooksSelector.setResult([ - { - id: 'firstId', - volumeInfo: { - title: 'First Title', - authors: ['First Author'], - }, - }, - { - id: 'secondId', - volumeInfo: { - title: 'Second Title', - authors: ['Second Author'], - }, - }, - ]); - - mockBookCollectionSelector.setResult([ - { - id: 'firstId', - volumeInfo: { - title: 'First Title', - authors: ['First Author'], - }, - }, - ]); - - store.refreshState(); - fixture.detectChanges(); - - expect( - fixture.debugElement.queryAll(By.css('.book-list .book-item')).length - ).toBe(2); - - expect( - fixture.debugElement.queryAll(By.css('.book-collection .book-item')) - .length - ).toBe(1); - }); - //#enddocregion mockSelector -}); - -//#docregion resetMockSelector -describe('AppComponent reset selectors', () => { - let store: MockStore; - - afterEach(() => { - store?.resetSelectors(); - }); - - it('should return the mocked value', (done: any) => { - TestBed.configureTestingModule({ - providers: [ - provideMockStore({ - selectors: [ - { - selector: selectBooks, - value: [ - { - id: 'mockedId', - volumeInfo: { - title: 'Mocked Title', - authors: ['Mocked Author'], - }, - }, - ], - }, - ], - }), - ], - }); - - store = TestBed.inject(MockStore); - - store.select(selectBooks).subscribe((mockBooks) => { - expect(mockBooks).toEqual([ - { - id: 'mockedId', - volumeInfo: { - title: 'Mocked Title', - authors: ['Mocked Author'], - }, - }, - ]); - done(); - }); - }); -}); -//#enddocregion resetMockSelector diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/tests/integration.spec.ts b/projects/www/src/app/examples/store-walkthrough/src/app/tests/integration.spec.ts deleted file mode 100644 index 18e599d13c..0000000000 --- a/projects/www/src/app/examples/store-walkthrough/src/app/tests/integration.spec.ts +++ /dev/null @@ -1,122 +0,0 @@ -import { - TestBed, - async, - ComponentFixture, - fakeAsync, - tick, -} from '@angular/core/testing'; -import { By } from '@angular/platform-browser'; -import { of } from 'rxjs'; -import { StoreModule } from '@ngrx/store'; -import { - HttpClientTestingModule, - HttpTestingController, -} from '@angular/common/http/testing'; - -import { BookListComponent } from './book-list/book-list.component'; -import { GoogleBooksService } from './book-list/books.service'; -import { BookCollectionComponent } from './book-collection/book-collection.component'; -import { AppComponent } from './app.component'; -import { collectionReducer } from './state/collection.reducer'; -import { booksReducer } from './state/books.reducer'; - -describe('AppComponent Integration Test', () => { - let component: AppComponent; - let fixture: ComponentFixture; - let booksService: GoogleBooksService; - let httpMock: HttpTestingController; - - beforeEach(async((done: any) => { - //#docregion integrate - TestBed.configureTestingModule({ - declarations: [AppComponent, BookListComponent, BookCollectionComponent], - imports: [ - HttpClientTestingModule, - StoreModule.forRoot({ - books: booksReducer, - collection: collectionReducer, - }), - ], - providers: [GoogleBooksService], - }).compileComponents(); - - fixture = TestBed.createComponent(AppComponent); - component = fixture.debugElement.componentInstance; - - fixture.detectChanges(); - //#enddocregion integrate - - booksService = TestBed.get(GoogleBooksService); - httpMock = TestBed.get(HttpTestingController); - - const req = httpMock.expectOne( - 'https://www.googleapis.com/books/v1/volumes?maxResults=5&orderBy=relevance&q=oliver%20sacks' - ); - req.flush({ - items: [ - { - id: 'firstId', - volumeInfo: { - title: 'First Title', - authors: ['First Author'], - }, - }, - { - id: 'secondId', - volumeInfo: { - title: 'Second Title', - authors: ['Second Author'], - }, - }, - ], - }); - - fixture.detectChanges(); - })); - - afterEach(() => { - httpMock.verify(); - }); - - it('should create the component', () => { - expect(component).toBeTruthy(); - }); - //#docregion addTest - describe('buttons should work as expected', () => { - it('should add to collection when add button is clicked and remove from collection when remove button is clicked', () => { - const addButton = getBookList()[1].query( - By.css('[data-test=add-button]') - ); - - click(addButton); - expect(getBookTitle(getCollection()[0])).toBe('Second Title'); - - const removeButton = getCollection()[0].query( - By.css('[data-test=remove-button]') - ); - click(removeButton); - - expect(getCollection().length).toBe(0); - }); - }); - - //functions used in the above test - function getCollection() { - return fixture.debugElement.queryAll(By.css('.book-collection .book-item')); - } - - function getBookList() { - return fixture.debugElement.queryAll(By.css('.book-list .book-item')); - } - - function getBookTitle(element) { - return element.query(By.css('p')).nativeElement.textContent; - } - - function click(element) { - const el: HTMLElement = element.nativeElement; - el.click(); - fixture.detectChanges(); - } - //#enddocregion addTest -}); diff --git a/projects/www/src/app/examples/store-walkthrough/src/app/book-collection/book-collection.component.css b/projects/www/src/app/examples/store-walkthrough/src/book-collection/book-collection.css similarity index 98% rename from projects/www/src/app/examples/store-walkthrough/src/app/book-collection/book-collection.component.css rename to projects/www/src/app/examples/store-walkthrough/src/book-collection/book-collection.css index 24469d9a62..fe3e6691ae 100644 --- a/projects/www/src/app/examples/store-walkthrough/src/app/book-collection/book-collection.component.css +++ b/projects/www/src/app/examples/store-walkthrough/src/book-collection/book-collection.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/store-walkthrough/src/book-collection/book-collection.ts b/projects/www/src/app/examples/store-walkthrough/src/book-collection/book-collection.ts new file mode 100644 index 0000000000..d0f585e450 --- /dev/null +++ b/projects/www/src/app/examples/store-walkthrough/src/book-collection/book-collection.ts @@ -0,0 +1,21 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { Book } from '../book-list/books.model'; + +@Component({ + selector: 'app-book-collection', + template: ` + @for(book of books; track book) { +
+

{{ book.volumeInfo.title }}

+ by {{ book.volumeInfo.authors }} + +
+ } + `, +}) +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 100% 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 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..50b490fc97 --- /dev/null +++ b/projects/www/src/app/examples/store-walkthrough/src/book-list/book-list.ts @@ -0,0 +1,21 @@ +import { Component, EventEmitter, Input, Output } from '@angular/core'; +import { Book } from './books.model'; + +@Component({ + selector: 'app-book-list', + template: ` + @for(book of books; track book) { +
+

{{ book.volumeInfo.title }}

+ by {{ book.volumeInfo.authors }} + +
+ } + `, +}) +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/books.model.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/books.model.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.ts similarity index 67% 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.ts index 266cc3ab37..c584b5571c 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.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 { Observable, map } from 'rxjs'; import { Book } from './books.model'; @Injectable({ providedIn: 'root' }) -export class GoogleBooksService { - constructor(private http: HttpClient) {} +export class GoogleBooks { + 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..792adf201c 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,15 @@ -import './polyfills'; - -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)); +import '@angular/compiler'; +import { bootstrapApplication } from '@angular/platform-browser'; +import { + mergeApplicationConfig, + provideZonelessChangeDetection, +} from '@angular/core'; +import { App } from './app'; +import { appConfig } from './app.config'; +import { provideHttpClient } from '@angular/common/http'; + +const config = mergeApplicationConfig(appConfig, { + providers: [provideZonelessChangeDetection(), provideHttpClient()], +}); + +bootstrapApplication(App, config); 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 100% 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 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 100% 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 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 100% 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 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 100% 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 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..d8f75139ef --- /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/books.ts: './src/book-list/books.ts' + src/book-list/books.model.ts: './src/book-list/books.model.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/pages/guide/store/walkthrough.md b/projects/www/src/app/pages/guide/store/walkthrough.md index 8b027695f4..23bf7f4201 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 `books.model.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. - - +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. + -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 `main.ts` file in order to make HTTP requests. + - +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. From 2fa62b740343f5de215a3fca50a7111462d5f3a1 Mon Sep 17 00:00:00 2001 From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com> Date: Fri, 19 Sep 2025 18:43:31 +0200 Subject: [PATCH 2/3] chore: run prettier on www directory --- projects/www/index.html | 3 +- projects/www/public/site.webmanifest | 34 +++--- .../www/src/app/examples/__base/index.html | 2 +- .../src/app/paginator.html | 112 +++++++++++------- .../src/app/paginator.scss | 3 +- .../src/index.html | 20 ++-- .../src/styles.scss | 3 +- .../src/app/paginator.html | 112 +++++++++++------- .../src/app/paginator.scss | 3 +- .../component-store-paginator/src/index.html | 20 ++-- .../component-store-paginator/src/styles.scss | 3 +- .../src/app/app.component.css | 2 +- .../src/index.html | 20 ++-- .../src/app/examples/ngrx-start/index.html | 2 +- .../src/app/app.component.css | 2 +- .../src/app/app.component.html | 8 +- .../router-store-selectors/src/index.html | 3 +- .../app/examples/store-walkthrough/index.html | 2 +- .../src/book-collection/book-collection.ts | 18 ++- .../src/book-list/book-list.css | 2 +- .../src/book-list/book-list.ts | 18 ++- .../testing-store/src/app/app.component.html | 5 +- .../book-collection.component.css | 2 +- .../book-collection.component.html | 15 +-- .../src/app/book-list/book-list.component.css | 2 +- .../app/book-list/book-list.component.html | 17 ++- .../app/examples/testing-store/src/index.html | 2 +- .../pages/guide/data/architecture-overview.md | 1 - .../app/pages/guide/data/entity-metadata.md | 4 +- .../app/pages/guide/signals/signal-state.md | 12 +- .../guide/signals/signal-store/events.md | 4 +- .../signals/signal-store/linked-state.md | 28 ++--- .../guide/signals/signal-store/testing.md | 2 +- .../store/configuration/runtime-checks.md | 4 +- .../src/app/pages/guide/store/selectors.md | 13 +- projects/www/src/styles.scss | 14 ++- 36 files changed, 272 insertions(+), 245 deletions(-) diff --git a/projects/www/index.html b/projects/www/index.html index 1dc9ca3ee9..ef35e8bb58 100644 --- a/projects/www/index.html +++ b/projects/www/index.html @@ -1,4 +1,4 @@ - + @@ -31,7 +31,6 @@ href="https://fonts.googleapis.com/css2?family=Oxanium:wght@200..800&family=Space+Mono:ital,wght@0,400;0,700;1,400;1,700&display=swap" rel="stylesheet" /> - diff --git a/projects/www/public/site.webmanifest b/projects/www/public/site.webmanifest index aa8f14478a..aa98c188e7 100644 --- a/projects/www/public/site.webmanifest +++ b/projects/www/public/site.webmanifest @@ -1,19 +1,19 @@ { - "name": "NgRx", - "short_name": "NgRx", - "icons": [ - { - "src": "/android-chrome-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "/android-chrome-512x512.png", - "sizes": "512x512", - "type": "image/png" - } - ], - "theme_color": "#000000", - "background_color": "#000000", - "display": "standalone" + "name": "NgRx", + "short_name": "NgRx", + "icons": [ + { + "src": "/android-chrome-192x192.png", + "sizes": "192x192", + "type": "image/png" + }, + { + "src": "/android-chrome-512x512.png", + "sizes": "512x512", + "type": "image/png" + } + ], + "theme_color": "#000000", + "background_color": "#000000", + "display": "standalone" } diff --git a/projects/www/src/app/examples/__base/index.html b/projects/www/src/app/examples/__base/index.html index 668d931247..2e15ba0163 100644 --- a/projects/www/src/app/examples/__base/index.html +++ b/projects/www/src/app/examples/__base/index.html @@ -1,4 +1,4 @@ - + diff --git a/projects/www/src/app/examples/component-store-paginator-service/src/app/paginator.html b/projects/www/src/app/examples/component-store-paginator-service/src/app/paginator.html index 504b40e936..ebba748544 100644 --- a/projects/www/src/app/examples/component-store-paginator-service/src/app/paginator.html +++ b/projects/www/src/app/examples/component-store-paginator-service/src/app/paginator.html @@ -1,17 +1,20 @@
-
- Items per page -
+
Items per page
+ class="mat-paginator-page-size-select" + > - + (selectionChange)="changePageSize($any($event).value)" + > + {{pageSizeOption}} @@ -19,61 +22,78 @@
{{vm.pageSize}}
+ *ngIf="vm.pageSizeOptions.length <= 1" + > + {{vm.pageSize}} +
-
- {{vm.rangeLabel}} -
+
{{vm.rangeLabel}}
- - - -
- \ No newline at end of file + diff --git a/projects/www/src/app/examples/component-store-paginator-service/src/app/paginator.scss b/projects/www/src/app/examples/component-store-paginator-service/src/app/paginator.scss index 484f431451..e938c98951 100644 --- a/projects/www/src/app/examples/component-store-paginator-service/src/app/paginator.scss +++ b/projects/www/src/app/examples/component-store-paginator-service/src/app/paginator.scss @@ -1,7 +1,6 @@ @import '~@angular/material/prebuilt-themes/indigo-pink.css'; /* Add application styles & imports to this file! */ - $mat-paginator-padding: 0 8px; $mat-paginator-page-size-margin-right: 8px; @@ -77,4 +76,4 @@ $mat-paginator-button-icon-size: 28px; [dir='rtl'] & { transform: rotate(180deg); } -} \ No newline at end of file +} diff --git a/projects/www/src/app/examples/component-store-paginator-service/src/index.html b/projects/www/src/app/examples/component-store-paginator-service/src/index.html index e17a125048..839ed013bb 100644 --- a/projects/www/src/app/examples/component-store-paginator-service/src/index.html +++ b/projects/www/src/app/examples/component-store-paginator-service/src/index.html @@ -1,13 +1,13 @@ - - - Paginator ComponentStore Example - - - - - - - + + + Paginator ComponentStore Example + + + + + + + diff --git a/projects/www/src/app/examples/component-store-paginator-service/src/styles.scss b/projects/www/src/app/examples/component-store-paginator-service/src/styles.scss index 484f431451..e938c98951 100644 --- a/projects/www/src/app/examples/component-store-paginator-service/src/styles.scss +++ b/projects/www/src/app/examples/component-store-paginator-service/src/styles.scss @@ -1,7 +1,6 @@ @import '~@angular/material/prebuilt-themes/indigo-pink.css'; /* Add application styles & imports to this file! */ - $mat-paginator-padding: 0 8px; $mat-paginator-page-size-margin-right: 8px; @@ -77,4 +76,4 @@ $mat-paginator-button-icon-size: 28px; [dir='rtl'] & { transform: rotate(180deg); } -} \ No newline at end of file +} diff --git a/projects/www/src/app/examples/component-store-paginator/src/app/paginator.html b/projects/www/src/app/examples/component-store-paginator/src/app/paginator.html index a37432e906..8c29a4576f 100644 --- a/projects/www/src/app/examples/component-store-paginator/src/app/paginator.html +++ b/projects/www/src/app/examples/component-store-paginator/src/app/paginator.html @@ -1,17 +1,20 @@
-
- Items per page -
+
Items per page
+ class="mat-paginator-page-size-select" + > - + (selectionChange)="changePageSize($any($event).value)" + > + {{pageSizeOption}} @@ -19,61 +22,78 @@
{{vm.pageSize}}
+ *ngIf="vm.pageSizeOptions.length <= 1" + > + {{vm.pageSize}} +
-
- {{vm.rangeLabel}} -
+
{{vm.rangeLabel}}
- - - -
- \ No newline at end of file + diff --git a/projects/www/src/app/examples/component-store-paginator/src/app/paginator.scss b/projects/www/src/app/examples/component-store-paginator/src/app/paginator.scss index 484f431451..e938c98951 100644 --- a/projects/www/src/app/examples/component-store-paginator/src/app/paginator.scss +++ b/projects/www/src/app/examples/component-store-paginator/src/app/paginator.scss @@ -1,7 +1,6 @@ @import '~@angular/material/prebuilt-themes/indigo-pink.css'; /* Add application styles & imports to this file! */ - $mat-paginator-padding: 0 8px; $mat-paginator-page-size-margin-right: 8px; @@ -77,4 +76,4 @@ $mat-paginator-button-icon-size: 28px; [dir='rtl'] & { transform: rotate(180deg); } -} \ No newline at end of file +} diff --git a/projects/www/src/app/examples/component-store-paginator/src/index.html b/projects/www/src/app/examples/component-store-paginator/src/index.html index e17a125048..839ed013bb 100644 --- a/projects/www/src/app/examples/component-store-paginator/src/index.html +++ b/projects/www/src/app/examples/component-store-paginator/src/index.html @@ -1,13 +1,13 @@ - - - Paginator ComponentStore Example - - - - - - - + + + Paginator ComponentStore Example + + + + + + + diff --git a/projects/www/src/app/examples/component-store-paginator/src/styles.scss b/projects/www/src/app/examples/component-store-paginator/src/styles.scss index 484f431451..e938c98951 100644 --- a/projects/www/src/app/examples/component-store-paginator/src/styles.scss +++ b/projects/www/src/app/examples/component-store-paginator/src/styles.scss @@ -1,7 +1,6 @@ @import '~@angular/material/prebuilt-themes/indigo-pink.css'; /* Add application styles & imports to this file! */ - $mat-paginator-padding: 0 8px; $mat-paginator-page-size-margin-right: 8px; @@ -77,4 +76,4 @@ $mat-paginator-button-icon-size: 28px; [dir='rtl'] & { transform: rotate(180deg); } -} \ No newline at end of file +} diff --git a/projects/www/src/app/examples/component-store-slide-toggle/src/app/app.component.css b/projects/www/src/app/examples/component-store-slide-toggle/src/app/app.component.css index b7ef084c56..ba43f5120f 100644 --- a/projects/www/src/app/examples/component-store-slide-toggle/src/app/app.component.css +++ b/projects/www/src/app/examples/component-store-slide-toggle/src/app/app.component.css @@ -1,3 +1,3 @@ p { font-family: Lato; -} \ No newline at end of file +} diff --git a/projects/www/src/app/examples/component-store-slide-toggle/src/index.html b/projects/www/src/app/examples/component-store-slide-toggle/src/index.html index 6be188edde..a4cf2092b2 100644 --- a/projects/www/src/app/examples/component-store-slide-toggle/src/index.html +++ b/projects/www/src/app/examples/component-store-slide-toggle/src/index.html @@ -1,13 +1,13 @@ - - - Slide-Toggle ComponentStore Example - - - - - - - + + + Slide-Toggle ComponentStore Example + + + + + + + diff --git a/projects/www/src/app/examples/ngrx-start/index.html b/projects/www/src/app/examples/ngrx-start/index.html index 17d565af7f..5805512ca7 100644 --- a/projects/www/src/app/examples/ngrx-start/index.html +++ b/projects/www/src/app/examples/ngrx-start/index.html @@ -1,4 +1,4 @@ - + diff --git a/projects/www/src/app/examples/router-store-selectors/src/app/app.component.css b/projects/www/src/app/examples/router-store-selectors/src/app/app.component.css index b7ef084c56..ba43f5120f 100644 --- a/projects/www/src/app/examples/router-store-selectors/src/app/app.component.css +++ b/projects/www/src/app/examples/router-store-selectors/src/app/app.component.css @@ -1,3 +1,3 @@ p { font-family: Lato; -} \ No newline at end of file +} diff --git a/projects/www/src/app/examples/router-store-selectors/src/app/app.component.html b/projects/www/src/app/examples/router-store-selectors/src/app/app.component.html index 6a65a85e9f..da14958631 100644 --- a/projects/www/src/app/examples/router-store-selectors/src/app/app.component.html +++ b/projects/www/src/app/examples/router-store-selectors/src/app/app.component.html @@ -1,7 +1,7 @@
    - -
  1. {{ car.make }} | {{ car.model}} | {{ car.year}} - + +
  2. {{ car.make }} | {{ car.model }} | {{ car.year }}
- \ No newline at end of file + diff --git a/projects/www/src/app/examples/router-store-selectors/src/index.html b/projects/www/src/app/examples/router-store-selectors/src/index.html index 6543fe0150..f8da00869e 100644 --- a/projects/www/src/app/examples/router-store-selectors/src/index.html +++ b/projects/www/src/app/examples/router-store-selectors/src/index.html @@ -1,4 +1,4 @@ - + @@ -11,4 +11,3 @@ - diff --git a/projects/www/src/app/examples/store-walkthrough/index.html b/projects/www/src/app/examples/store-walkthrough/index.html index 17d565af7f..5805512ca7 100644 --- a/projects/www/src/app/examples/store-walkthrough/index.html +++ b/projects/www/src/app/examples/store-walkthrough/index.html @@ -1,4 +1,4 @@ - + diff --git a/projects/www/src/app/examples/store-walkthrough/src/book-collection/book-collection.ts b/projects/www/src/app/examples/store-walkthrough/src/book-collection/book-collection.ts index d0f585e450..1e7c518ff8 100644 --- a/projects/www/src/app/examples/store-walkthrough/src/book-collection/book-collection.ts +++ b/projects/www/src/app/examples/store-walkthrough/src/book-collection/book-collection.ts @@ -4,18 +4,16 @@ import { Book } from '../book-list/books.model'; @Component({ selector: 'app-book-collection', template: ` - @for(book of books; track book) { -
-

{{ book.volumeInfo.title }}

- by {{ book.volumeInfo.authors }} - -
+ @for (book of books; track book) { +
+

{{ book.volumeInfo.title }}

+ by {{ book.volumeInfo.authors }} + +
} `, }) export class BookCollection { - @Input() - books: ReadonlyArray = []; - @Output() - remove = new EventEmitter(); + @Input() books: ReadonlyArray = []; + @Output() remove = new EventEmitter(); } diff --git a/projects/www/src/app/examples/store-walkthrough/src/book-list/book-list.css b/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/book-list/book-list.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 index 50b490fc97..9421bb3282 100644 --- 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 @@ -4,18 +4,16 @@ import { Book } from './books.model'; @Component({ selector: 'app-book-list', template: ` - @for(book of books; track book) { -
-

{{ book.volumeInfo.title }}

- by {{ book.volumeInfo.authors }} - -
+ @for (book of books; track book) { +
+

{{ book.volumeInfo.title }}

+ by {{ book.volumeInfo.authors }} + +
} `, }) export class BookList { - @Input() - books: ReadonlyArray = []; - @Output() - add = new EventEmitter(); + @Input() books: ReadonlyArray = []; + @Output() add = new EventEmitter(); } 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}} - +
+

{{ book.volumeInfo.title }}

+ by {{ book.volumeInfo.authors }} +
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}} - -
\ No newline at end of file +
+

{{ book.volumeInfo.title }}

+ by {{ book.volumeInfo.authors }} + +
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';

Books

@if (store.isLoading()) { -

Loading...

+

Loading...

} @else { -
    - @for (book of store.books(); track book.id) { -
  • {{ book.title }}
  • - } -
+
    + @for (book of store.books(); track book.id) { +
  • {{ book.title }}
  • + } +
} `, providers: [BookListStore], diff --git a/projects/www/src/app/pages/guide/signals/signal-store/events.md b/projects/www/src/app/pages/guide/signals/signal-store/events.md index 79a7877bee..1ddd839fc9 100644 --- a/projects/www/src/app/pages/guide/signals/signal-store/events.md +++ b/projects/www/src/app/pages/guide/signals/signal-store/events.md @@ -286,12 +286,12 @@ import { BookSearchStore } from './book-search-store'; @if (store.isLoading()) { -

Loading...

+

Loading...

}
    @for (book of store.books(); track book.id) { -
  • {{ book.title }}
  • +
  • {{ book.title }}
  • }
`, diff --git a/projects/www/src/app/pages/guide/signals/signal-store/linked-state.md b/projects/www/src/app/pages/guide/signals/signal-store/linked-state.md index e8efb77eec..5cedf2aa2c 100644 --- a/projects/www/src/app/pages/guide/signals/signal-store/linked-state.md +++ b/projects/www/src/app/pages/guide/signals/signal-store/linked-state.md @@ -24,20 +24,20 @@ import { } from '@ngrx/signals'; export const OptionsStore = signalStore( - withState({ options: [1, 2, 3] }), - withLinkedState(({ options }) => ({ - // 👇 Defining a linked state slice. - selectedOption: () => options()[0] ?? undefined, - })), - withMethods((store) => ({ - setOptions(options: number[]): void { - patchState(store, { options }); - }, - setSelectedOption(selectedOption: number): void { - // 👇 Updating a linked state slice. - patchState(store, { selectedOption }); - }, - })), + withState({ options: [1, 2, 3] }), + withLinkedState(({ options }) => ({ + // 👇 Defining a linked state slice. + selectedOption: () => options()[0] ?? undefined, + })), + withMethods((store) => ({ + setOptions(options: number[]): void { + patchState(store, { options }); + }, + setSelectedOption(selectedOption: number): void { + // 👇 Updating a linked state slice. + patchState(store, { selectedOption }); + }, + })) ); ``` diff --git a/projects/www/src/app/pages/guide/signals/signal-store/testing.md b/projects/www/src/app/pages/guide/signals/signal-store/testing.md index e6c973a626..9224c4421e 100644 --- a/projects/www/src/app/pages/guide/signals/signal-store/testing.md +++ b/projects/www/src/app/pages/guide/signals/signal-store/testing.md @@ -508,7 +508,7 @@ The `MovieComponent` utilizes the `MoviesStore` to display movies:
    @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/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 From df8a9e96ae93379c1d0e11f2bbb22fc484c84504 Mon Sep 17 00:00:00 2001 From: Tim Deschryver <28659384+timdeschryver@users.noreply.github.com> Date: Fri, 19 Sep 2025 18:50:12 +0200 Subject: [PATCH 3/3] docs: update examples --- .../src/app/examples/ngrx-start/src/app.config.ts | 7 +++++-- projects/www/src/app/examples/ngrx-start/src/main.ts | 10 +--------- .../app/examples/store-walkthrough/src/app.config.ts | 8 +++++++- .../src/app/examples/store-walkthrough/src/app.ts | 4 ++-- .../src/book-collection/book-collection.ts | 2 +- .../store-walkthrough/src/book-list/book-list.ts | 2 +- .../src/book-list/{books.model.ts => book.ts} | 0 .../src/book-list/{books.ts => books-service.ts} | 4 ++-- .../src/app/examples/store-walkthrough/src/main.ts | 11 +---------- .../store-walkthrough/src/state/app.state.ts | 2 +- .../store-walkthrough/src/state/books.actions.ts | 2 +- .../store-walkthrough/src/state/books.reducer.ts | 2 +- .../store-walkthrough/src/state/books.selectors.ts | 2 +- .../app/examples/store-walkthrough/stackblitz.yml | 4 ++-- .../www/src/app/pages/guide/store/walkthrough.md | 12 ++++++------ 15 files changed, 32 insertions(+), 40 deletions(-) rename projects/www/src/app/examples/store-walkthrough/src/book-list/{books.model.ts => book.ts} (100%) rename projects/www/src/app/examples/store-walkthrough/src/book-list/{books.ts => books-service.ts} (88%) diff --git a/projects/www/src/app/examples/ngrx-start/src/app.config.ts b/projects/www/src/app/examples/ngrx-start/src/app.config.ts index 81a6edde41..3b11dcffb8 100644 --- a/projects/www/src/app/examples/ngrx-start/src/app.config.ts +++ b/projects/www/src/app/examples/ngrx-start/src/app.config.ts @@ -1,5 +1,8 @@ -import { ApplicationConfig } from '@angular/core'; +import { + ApplicationConfig, + provideZonelessChangeDetection, +} from '@angular/core'; export const appConfig: ApplicationConfig = { - providers: [], + providers: [provideZonelessChangeDetection()], }; diff --git a/projects/www/src/app/examples/ngrx-start/src/main.ts b/projects/www/src/app/examples/ngrx-start/src/main.ts index df19f9c747..363eedc107 100644 --- a/projects/www/src/app/examples/ngrx-start/src/main.ts +++ b/projects/www/src/app/examples/ngrx-start/src/main.ts @@ -1,14 +1,6 @@ import '@angular/compiler'; import { bootstrapApplication } from '@angular/platform-browser'; -import { - mergeApplicationConfig, - provideZonelessChangeDetection, -} from '@angular/core'; import { App } from './app'; import { appConfig } from './app.config'; -const config = mergeApplicationConfig(appConfig, { - providers: [provideZonelessChangeDetection()], -}); - -bootstrapApplication(App, config); +bootstrapApplication(App, appConfig); diff --git a/projects/www/src/app/examples/store-walkthrough/src/app.config.ts b/projects/www/src/app/examples/store-walkthrough/src/app.config.ts index 4809ebc21f..90d04c6036 100644 --- a/projects/www/src/app/examples/store-walkthrough/src/app.config.ts +++ b/projects/www/src/app/examples/store-walkthrough/src/app.config.ts @@ -1,4 +1,8 @@ -import { ApplicationConfig } from '@angular/core'; +import { + ApplicationConfig, + provideZonelessChangeDetection, +} from '@angular/core'; +import { provideHttpClient } from '@angular/common/http'; import { provideStore } from '@ngrx/store'; import { booksReducer } from './state/books.reducer'; @@ -6,6 +10,8 @@ import { collectionReducer } from './state/collection.reducer'; export const appConfig: ApplicationConfig = { providers: [ + provideZonelessChangeDetection(), + provideHttpClient(), provideStore({ books: booksReducer, collection: collectionReducer, diff --git a/projects/www/src/app/examples/store-walkthrough/src/app.ts b/projects/www/src/app/examples/store-walkthrough/src/app.ts index ae2d8b62a2..eaa4cd10c2 100644 --- a/projects/www/src/app/examples/store-walkthrough/src/app.ts +++ b/projects/www/src/app/examples/store-walkthrough/src/app.ts @@ -3,7 +3,7 @@ import { Store } from '@ngrx/store'; import { selectBookCollection, selectBooks } from './state/books.selectors'; import { BooksActions, BooksApiActions } from './state/books.actions'; -import { GoogleBooks } from './book-list/books'; +import { GoogleBooksService } from './book-list/books-service'; import { BookList } from './book-list/book-list'; import { BookCollection } from './book-collection/book-collection'; @@ -24,7 +24,7 @@ import { BookCollection } from './book-collection/book-collection'; imports: [BookList, BookCollection], }) export class App implements OnInit { - private readonly booksService = inject(GoogleBooks); + private readonly booksService = inject(GoogleBooksService); private readonly store = inject(Store); protected books = this.store.selectSignal(selectBooks); diff --git a/projects/www/src/app/examples/store-walkthrough/src/book-collection/book-collection.ts b/projects/www/src/app/examples/store-walkthrough/src/book-collection/book-collection.ts index 1e7c518ff8..7eaf09f969 100644 --- a/projects/www/src/app/examples/store-walkthrough/src/book-collection/book-collection.ts +++ b/projects/www/src/app/examples/store-walkthrough/src/book-collection/book-collection.ts @@ -1,5 +1,5 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Book } from '../book-list/books.model'; +import { Book } from '../book-list/book'; @Component({ selector: 'app-book-collection', 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 index 9421bb3282..851552c172 100644 --- 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 @@ -1,5 +1,5 @@ import { Component, EventEmitter, Input, Output } from '@angular/core'; -import { Book } from './books.model'; +import { Book } from './book'; @Component({ selector: 'app-book-list', diff --git a/projects/www/src/app/examples/store-walkthrough/src/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/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/book-list/books.ts b/projects/www/src/app/examples/store-walkthrough/src/book-list/books-service.ts similarity index 88% rename from projects/www/src/app/examples/store-walkthrough/src/book-list/books.ts rename to projects/www/src/app/examples/store-walkthrough/src/book-list/books-service.ts index c584b5571c..d6b5fb8b16 100644 --- a/projects/www/src/app/examples/store-walkthrough/src/book-list/books.ts +++ b/projects/www/src/app/examples/store-walkthrough/src/book-list/books-service.ts @@ -2,10 +2,10 @@ import { HttpClient } from '@angular/common/http'; import { inject, Injectable } from '@angular/core'; import { Observable, map } from 'rxjs'; -import { Book } from './books.model'; +import { Book } from './book'; @Injectable({ providedIn: 'root' }) -export class GoogleBooks { +export class GoogleBooksService { private readonly http = inject(HttpClient); getBooks(): Observable> { 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 792adf201c..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,15 +1,6 @@ import '@angular/compiler'; import { bootstrapApplication } from '@angular/platform-browser'; -import { - mergeApplicationConfig, - provideZonelessChangeDetection, -} from '@angular/core'; import { App } from './app'; import { appConfig } from './app.config'; -import { provideHttpClient } from '@angular/common/http'; -const config = mergeApplicationConfig(appConfig, { - providers: [provideZonelessChangeDetection(), provideHttpClient()], -}); - -bootstrapApplication(App, config); +bootstrapApplication(App, appConfig); diff --git a/projects/www/src/app/examples/store-walkthrough/src/state/app.state.ts b/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/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/state/books.actions.ts b/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/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/state/books.reducer.ts b/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/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/state/books.selectors.ts b/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/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/stackblitz.yml b/projects/www/src/app/examples/store-walkthrough/stackblitz.yml index d8f75139ef..7ca3714e3e 100644 --- a/projects/www/src/app/examples/store-walkthrough/stackblitz.yml +++ b/projects/www/src/app/examples/store-walkthrough/stackblitz.yml @@ -13,8 +13,8 @@ files: 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/books.ts: './src/book-list/books.ts' - src/book-list/books.model.ts: './src/book-list/books.model.ts' + 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/pages/guide/store/walkthrough.md b/projects/www/src/app/pages/guide/store/walkthrough.md index 23bf7f4201..2918958b13 100644 --- a/projects/www/src/app/pages/guide/store/walkthrough.md +++ b/projects/www/src/app/pages/guide/store/walkthrough.md @@ -8,12 +8,12 @@ The full example is available on StackBlitz: ## 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 `books.model.ts` to reference different aspects of a book in the book list. +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. - + -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. +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. @@ -40,12 +40,12 @@ The full example is available on StackBlitz: 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. - + -8. Add the `HttpClient` module using the `provideHttpClient` provider in the `main.ts` file in order to make HTTP requests. +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.