withFeatureFactory51 |
Current User: {{ userStore.entity()?.name || '-' }}
56 | `, 57 | imports: [MatButton, FormsModule], 58 | }) 59 | export class FeatureFactoryComponent { 60 | protected readonly userStore = inject(UserStore); 61 | 62 | loadUser() { 63 | void this.userStore.load(1); 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /apps/demo/src/app/flight-search-data-service-dynamic/flight-booking.store.ts: -------------------------------------------------------------------------------- 1 | import { FlightService } from '../shared/flight.service'; 2 | 3 | import { signalStore, type } from '@ngrx/signals'; 4 | 5 | import { withEntities } from '@ngrx/signals/entities'; 6 | import { 7 | withCallState, 8 | withDataService, 9 | withUndoRedo, 10 | } from '@angular-architects/ngrx-toolkit'; 11 | import { Flight } from '../shared/flight'; 12 | 13 | export const FlightBookingStore = signalStore( 14 | { providedIn: 'root' }, 15 | withCallState({ 16 | collection: 'flight', 17 | }), 18 | withEntities({ 19 | entity: type{{ selected() | json }}71 | -------------------------------------------------------------------------------- /apps/demo/src/app/flight-search-data-service-dynamic/flight-search.component.ts: -------------------------------------------------------------------------------- 1 | import { JsonPipe, NgForOf, NgIf } from '@angular/common'; 2 | import { Component, inject } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { FlightCardComponent } from '../shared/flight-card.component'; 5 | import { RouterLink } from '@angular/router'; 6 | import { FlightBookingStore } from './flight-booking.store'; 7 | 8 | @Component({ 9 | imports: [ 10 | NgIf, 11 | NgForOf, 12 | JsonPipe, 13 | FormsModule, 14 | FlightCardComponent, 15 | RouterLink, 16 | ], 17 | selector: 'demo-flight-search', 18 | templateUrl: './flight-search.component.html', 19 | }) 20 | export class FlightSearchDynamicComponent { 21 | private store = inject(FlightBookingStore); 22 | 23 | from = this.store.flightFilter.from; 24 | to = this.store.flightFilter.to; 25 | flights = this.store.flightEntities; 26 | selected = this.store.selectedFlightEntities; 27 | selectedIds = this.store.selectedFlightIds; 28 | 29 | loading = this.store.flightLoading; 30 | 31 | canUndo = this.store.canUndo; 32 | canRedo = this.store.canRedo; 33 | 34 | async search() { 35 | this.store.loadFlightEntities(); 36 | } 37 | 38 | undo(): void { 39 | this.store.undo(); 40 | } 41 | 42 | redo(): void { 43 | this.store.redo(); 44 | } 45 | 46 | updateCriteria(from: string, to: string): void { 47 | this.store.updateFlightFilter({ from, to }); 48 | } 49 | 50 | updateBasket(id: number, selected: boolean): void { 51 | this.store.updateSelectedFlightEntities(id, selected); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /apps/demo/src/app/flight-search-data-service-simple/flight-booking-simple.store.ts: -------------------------------------------------------------------------------- 1 | import { FlightService } from '../shared/flight.service'; 2 | 3 | import { signalStore } from '@ngrx/signals'; 4 | 5 | import { withEntities } from '@ngrx/signals/entities'; 6 | import { 7 | withCallState, 8 | withDataService, 9 | withUndoRedo, 10 | } from '@angular-architects/ngrx-toolkit'; 11 | import { Flight } from '../shared/flight'; 12 | 13 | export const SimpleFlightBookingStore = signalStore( 14 | { providedIn: 'root' }, 15 | withCallState(), 16 | withEntities
{{ selected() | json }}76 | -------------------------------------------------------------------------------- /apps/demo/src/app/flight-search-data-service-simple/flight-search-simple.component.ts: -------------------------------------------------------------------------------- 1 | import { JsonPipe, NgForOf, NgIf } from '@angular/common'; 2 | import { Component, inject } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { ChangeDetectionStrategy } from '@angular/core'; 5 | import { RouterLink } from '@angular/router'; 6 | import { FlightCardComponent } from '../shared/flight-card.component'; 7 | import { SimpleFlightBookingStore } from './flight-booking-simple.store'; 8 | import { MatTableModule } from '@angular/material/table'; 9 | import { MatInputModule } from '@angular/material/input'; 10 | import { MatButtonModule } from '@angular/material/button'; 11 | 12 | @Component({ 13 | imports: [ 14 | NgIf, 15 | NgForOf, 16 | JsonPipe, 17 | FormsModule, 18 | FlightCardComponent, 19 | MatTableModule, 20 | MatInputModule, 21 | MatButtonModule, 22 | RouterLink, 23 | ], 24 | selector: 'demo-flight-search', 25 | templateUrl: './flight-search-simple.component.html', 26 | changeDetection: ChangeDetectionStrategy.OnPush, 27 | }) 28 | export class FlightSearchSimpleComponent { 29 | private store = inject(SimpleFlightBookingStore); 30 | 31 | from = this.store.filter.from; 32 | to = this.store.filter.to; 33 | flights = this.store.entities; 34 | selected = this.store.selectedEntities; 35 | selectedIds = this.store.selectedIds; 36 | 37 | loading = this.store.loading; 38 | 39 | canUndo = this.store.canUndo; 40 | canRedo = this.store.canRedo; 41 | 42 | async search() { 43 | this.store.load(); 44 | } 45 | 46 | undo(): void { 47 | this.store.undo(); 48 | } 49 | 50 | redo(): void { 51 | this.store.redo(); 52 | } 53 | 54 | updateCriteria(from: string, to: string): void { 55 | this.store.updateFilter({ from, to }); 56 | } 57 | 58 | updateBasket(id: number, selected: boolean): void { 59 | this.store.updateSelected(id, selected); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /apps/demo/src/app/flight-search-redux-connector/+state/actions.ts: -------------------------------------------------------------------------------- 1 | import { createActionGroup, emptyProps, props } from "@ngrx/store"; 2 | import { FlightFilter } from "../../shared/flight.service"; 3 | import { Flight } from "../../shared/flight"; 4 | 5 | 6 | export const ticketActions = createActionGroup({ 7 | source: 'tickets', 8 | events: { 9 | 'flights load': props
{{ localState.basket() | json }}57 | -------------------------------------------------------------------------------- /apps/demo/src/app/flight-search-redux-connector/flight-search.component.ts: -------------------------------------------------------------------------------- 1 | import { JsonPipe } from '@angular/common'; 2 | import { Component } from '@angular/core'; 3 | import { FormsModule } from '@angular/forms'; 4 | import { FlightCardComponent } from '../shared/flight-card.component'; 5 | import { ticketActions } from './+state/actions'; 6 | import { injectFlightStore } from './+state/redux'; 7 | import { patchState, signalState } from '@ngrx/signals'; 8 | import { FlightFilter } from '../shared/flight.service'; 9 | import { Flight } from '../shared/flight'; 10 | 11 | @Component({ 12 | imports: [JsonPipe, FormsModule, FlightCardComponent], 13 | selector: 'demo-flight-search-redux-connector', 14 | templateUrl: './flight-search.component.html', 15 | }) 16 | export class FlightSearchReducConnectorComponent { 17 | private store = injectFlightStore(); 18 | 19 | protected localState = signalState({ 20 | filter: { 21 | from: 'Frankfurt', 22 | to: 'Paris', 23 | }, 24 | basket: { 25 | 888: true, 26 | 889: true, 27 | } as Record
withImmutableState26 |
28 | withImmutableState throws an error if the state is mutated, regardless 29 | inside or outside the SignalStore. 30 |
31 |Form to edit State mutable via ngModel
45 | 46 | `, 47 | imports: [MatButton, FormsModule], 48 | }) 49 | export class ImmutableStateComponent { 50 | protected readonly userStore = inject(UserStore); 51 | mutateOutside() { 52 | initialState.user.id = 2; 53 | } 54 | 55 | mutateInside() { 56 | this.userStore.mutateState(); 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /apps/demo/src/app/lazy-routes.ts: -------------------------------------------------------------------------------- 1 | import { Route } from '@angular/router'; 2 | import { FlightSearchComponent } from './flight-search/flight-search.component'; 3 | import { FlightSearchSimpleComponent } from './flight-search-data-service-simple/flight-search-simple.component'; 4 | import { FlightEditSimpleComponent } from './flight-search-data-service-simple/flight-edit-simple.component'; 5 | import { FlightSearchDynamicComponent } from './flight-search-data-service-dynamic/flight-search.component'; 6 | import { FlightEditDynamicComponent } from './flight-search-data-service-dynamic/flight-edit.component'; 7 | import { TodoStorageSyncComponent } from './todo-storage-sync/todo-storage-sync.component'; 8 | import { FlightSearchWithPaginationComponent } from './flight-search-with-pagination/flight-search-with-pagination.component'; 9 | import { FlightSearchReducConnectorComponent } from './flight-search-redux-connector/flight-search.component'; 10 | import { provideFlightStore } from './flight-search-redux-connector/+state/redux'; 11 | import { TodoComponent } from './devtools/todo.component'; 12 | import { TodoIndexeddbSyncComponent } from './todo-indexeddb-sync/todo-indexeddb-sync.component'; 13 | 14 | export const lazyRoutes: Route[] = [ 15 | { path: 'todo', component: TodoComponent }, 16 | { path: 'flight-search', component: FlightSearchComponent }, 17 | { 18 | path: 'flight-search-data-service-simple', 19 | component: FlightSearchSimpleComponent, 20 | }, 21 | { path: 'flight-edit-simple/:id', component: FlightEditSimpleComponent }, 22 | { 23 | path: 'flight-search-data-service-dynamic', 24 | component: FlightSearchDynamicComponent, 25 | }, 26 | { 27 | path: 'flight-search-with-pagination', 28 | component: FlightSearchWithPaginationComponent, 29 | }, 30 | { path: 'flight-edit-dynamic/:id', component: FlightEditDynamicComponent }, 31 | { path: 'todo-storage-sync', component: TodoStorageSyncComponent }, 32 | { path: 'todo-indexeddb-sync', component: TodoIndexeddbSyncComponent }, 33 | { 34 | path: 'flight-search-redux-connector', 35 | providers: [provideFlightStore()], 36 | component: FlightSearchReducConnectorComponent, 37 | }, 38 | { 39 | path: 'reset', 40 | loadComponent: () => 41 | import('./reset/todo.component').then((m) => m.TodoComponent), 42 | }, 43 | { 44 | path: 'immutable-state', 45 | loadComponent: () => 46 | import('./immutable-state/immutable-state.component').then( 47 | (m) => m.ImmutableStateComponent 48 | ), 49 | }, 50 | { 51 | path: 'feature-factory', 52 | loadComponent: () => 53 | import('./feature-factory/feature-factory.component').then( 54 | (m) => m.FeatureFactoryComponent 55 | ), 56 | }, 57 | { 58 | path: 'conditional', 59 | loadComponent: () => 60 | import('./with-conditional/conditional.component').then( 61 | (m) => m.ConditionalSettingComponent 62 | ), 63 | }, 64 | ]; 65 | -------------------------------------------------------------------------------- /apps/demo/src/app/reset/todo-store.ts: -------------------------------------------------------------------------------- 1 | import { 2 | getState, 3 | patchState, 4 | signalStore, 5 | withHooks, 6 | withMethods, 7 | withState, 8 | } from '@ngrx/signals'; 9 | import { addEntity, updateEntity, withEntities } from '@ngrx/signals/entities'; 10 | import { setResetState, withReset } from '@angular-architects/ngrx-toolkit'; 11 | 12 | export interface Todo { 13 | id: number; 14 | name: string; 15 | finished: boolean; 16 | description?: string; 17 | deadline?: Date; 18 | } 19 | 20 | export type AddTodo = OmitFlight-No.: #{{item.id}}
9 |Date: {{item.date | date:'dd.MM.yyyy HH:mm:ss'}}
10 |
11 |
12 |
13 |
Current User {{ userStore.name() }}
`, 52 | providers: [UserStore], 53 | }) 54 | class ConditionalUserComponent { 55 | protected readonly userStore = inject(UserStore); 56 | 57 | constructor() { 58 | console.log('log geht es'); 59 | } 60 | } 61 | 62 | @Component({ 63 | template: ` 64 |withConditional66 |
docs
directory.
29 | >
30 | ),
31 | },
32 | {
33 | title: 'Powered by React',
34 | Svg: require('@site/static/img/undraw_docusaurus_react.svg').default,
35 | description: (
36 | <>
37 | Extend or customize your website layout by reusing React. Docusaurus can
38 | be extended while reusing the same header and footer.
39 | >
40 | ),
41 | },
42 | ];
43 |
44 | function Feature({ title, Svg, description }: FeatureItem) {
45 | return (
46 | {description}
53 |{siteConfig.tagline}
22 |