Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Introducing NgRx in an Nx Angular Workspace

Introducing NgRx in an Nx Angular Workspace

In today's dynamic software development landscape, creating scalable and maintainable Angular applications is a paramount challenge. Nx Workspace, with its powerful capabilities for monorepo management, and NgRx, a state management library for Angular, have emerged as essential tools for achieving this goal. This talk explores how you can seamlessly integrate NgRx into an Nx Workspace, enabling you to build robust and maintainable Angular applications.
This talk explores Nx Workspaces and NgRx, learning how to structure your workspace for maximum efficiency, create feature modules, and manage state using NgRx's store, effects, and selectors. We'll cover best practices for organizing code, managing dependencies, and optimizing build and test processes. By the end of this talk, you'll have a solid understanding of how to harness the full potential of NgRx within an Nx Workspace, ensuring the scalability and maintainability of your Angular applications.

Fabian Gosebrink

September 20, 2024
Tweet

More Decks by Fabian Gosebrink

Other Decks in Technology

Transcript

  1. #1

  2. #1

  3. export class ContentComponent implements OnInit { private readonly service =

    inject(Service); items: Todo[]; doneItems: Todo[]; ngOnInit() { this.service.getData() .subscribe(data => this.items = data); this.service.detDoneItems() .subscribe(data => this.doneItems = data); } addTodo(item: string) { // ... } markAsDone(item: Todo) { // ... } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  4. export class ContentComponent implements OnInit { private readonly service =

    inject(Service); items: Todo[]; doneItems: Todo[]; ngOnInit() { this.service.getData() .subscribe(data => this.items = data); this.service.detDoneItems() .subscribe(data => this.doneItems = data); } addTodo(item: string) { // ... } markAsDone(item: Todo) { // ... } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private readonly service = inject(Service); export class ContentComponent implements OnInit { 1 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22
  5. export class ContentComponent implements OnInit { private readonly service =

    inject(Service); items: Todo[]; doneItems: Todo[]; ngOnInit() { this.service.getData() .subscribe(data => this.items = data); this.service.detDoneItems() .subscribe(data => this.doneItems = data); } addTodo(item: string) { // ... } markAsDone(item: Todo) { // ... } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private readonly service = inject(Service); export class ContentComponent implements OnInit { 1 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22 items: Todo[]; doneItems: Todo[]; export class ContentComponent implements OnInit { 1 private readonly service = inject(Service); 2 3 4 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22
  6. export class ContentComponent implements OnInit { private readonly service =

    inject(Service); items: Todo[]; doneItems: Todo[]; ngOnInit() { this.service.getData() .subscribe(data => this.items = data); this.service.detDoneItems() .subscribe(data => this.doneItems = data); } addTodo(item: string) { // ... } markAsDone(item: Todo) { // ... } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private readonly service = inject(Service); export class ContentComponent implements OnInit { 1 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22 items: Todo[]; doneItems: Todo[]; export class ContentComponent implements OnInit { 1 private readonly service = inject(Service); 2 3 4 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22 this.service.getData() .subscribe(data => this.items = data); export class ContentComponent implements OnInit { 1 private readonly service = inject(Service); 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 8 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22
  7. export class ContentComponent implements OnInit { private readonly service =

    inject(Service); items: Todo[]; doneItems: Todo[]; ngOnInit() { this.service.getData() .subscribe(data => this.items = data); this.service.detDoneItems() .subscribe(data => this.doneItems = data); } addTodo(item: string) { // ... } markAsDone(item: Todo) { // ... } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private readonly service = inject(Service); export class ContentComponent implements OnInit { 1 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22 items: Todo[]; doneItems: Todo[]; export class ContentComponent implements OnInit { 1 private readonly service = inject(Service); 2 3 4 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22 this.service.getData() .subscribe(data => this.items = data); export class ContentComponent implements OnInit { 1 private readonly service = inject(Service); 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 8 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22 this.service.detDoneItems() .subscribe(data => this.doneItems = data); export class ContentComponent implements OnInit { 1 private readonly service = inject(Service); 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 11 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22
  8. export class ContentComponent implements OnInit { private readonly service =

    inject(Service); items: Todo[]; doneItems: Todo[]; ngOnInit() { this.service.getData() .subscribe(data => this.items = data); this.service.detDoneItems() .subscribe(data => this.doneItems = data); } addTodo(item: string) { // ... } markAsDone(item: Todo) { // ... } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private readonly service = inject(Service); export class ContentComponent implements OnInit { 1 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22 items: Todo[]; doneItems: Todo[]; export class ContentComponent implements OnInit { 1 private readonly service = inject(Service); 2 3 4 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22 this.service.getData() .subscribe(data => this.items = data); export class ContentComponent implements OnInit { 1 private readonly service = inject(Service); 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 8 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22 this.service.detDoneItems() .subscribe(data => this.doneItems = data); export class ContentComponent implements OnInit { 1 private readonly service = inject(Service); 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 11 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22 addTodo(item: string) { // ... } export class ContentComponent implements OnInit { 1 private readonly service = inject(Service); 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 15 16 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22
  9. export class ContentComponent implements OnInit { private readonly service =

    inject(Service); items: Todo[]; doneItems: Todo[]; ngOnInit() { this.service.getData() .subscribe(data => this.items = data); this.service.detDoneItems() .subscribe(data => this.doneItems = data); } addTodo(item: string) { // ... } markAsDone(item: Todo) { // ... } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 private readonly service = inject(Service); export class ContentComponent implements OnInit { 1 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22 items: Todo[]; doneItems: Todo[]; export class ContentComponent implements OnInit { 1 private readonly service = inject(Service); 2 3 4 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22 this.service.getData() .subscribe(data => this.items = data); export class ContentComponent implements OnInit { 1 private readonly service = inject(Service); 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 8 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22 this.service.detDoneItems() .subscribe(data => this.doneItems = data); export class ContentComponent implements OnInit { 1 private readonly service = inject(Service); 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 11 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22 addTodo(item: string) { // ... } export class ContentComponent implements OnInit { 1 private readonly service = inject(Service); 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 15 16 17 18 markAsDone(item: Todo) { 19 // ... 20 } 21 } 22 markAsDone(item: Todo) { // ... } export class ContentComponent implements OnInit { 1 private readonly service = inject(Service); 2 3 items: Todo[]; 4 doneItems: Todo[]; 5 6 ngOnInit() { 7 this.service.getData() 8 .subscribe(data => this.items = data); 9 10 this.service.detDoneItems() 11 .subscribe(data => this.doneItems = data); 12 } 13 14 addTodo(item: string) { 15 // ... 16 } 17 18 19 20 21 } 22
  10. <div> <app-todo-form (todoAdded)="addTodo($event)"> </app-todo-form> <app-todo-list [items]="items" [doneItems]="doneItems" (markAsDone)="markAsDone($event)" ></app-todo-list> </div>

    1 2 3 4 5 6 7 8 9 10 11 <app-todo-form (todoAdded)="addTodo($event)"> </app-todo-form> <div> 1 2 3 4 5 <app-todo-list 6 [items]="items" 7 [doneItems]="doneItems" 8 (markAsDone)="markAsDone($event)" 9 ></app-todo-list> 10 </div> 11
  11. <div> <app-todo-form (todoAdded)="addTodo($event)"> </app-todo-form> <app-todo-list [items]="items" [doneItems]="doneItems" (markAsDone)="markAsDone($event)" ></app-todo-list> </div>

    1 2 3 4 5 6 7 8 9 10 11 <app-todo-form (todoAdded)="addTodo($event)"> </app-todo-form> <div> 1 2 3 4 5 <app-todo-list 6 [items]="items" 7 [doneItems]="doneItems" 8 (markAsDone)="markAsDone($event)" 9 ></app-todo-list> 10 </div> 11 <app-todo-list [items]="items" [doneItems]="doneItems" (markAsDone)="markAsDone($event)" ></app-todo-list> <div> 1 <app-todo-form 2 (todoAdded)="addTodo($event)"> 3 </app-todo-form> 4 5 6 7 8 9 10 </div> 11
  12. export class TodoListComponent { items = input<Todo[]>([]) doneItems = input<Todo[]>([])

    markAsDone = output<Todo>(); moveToDone(item: Todo) { this.markAsDone.emit(item); } } 1 2 3 4 5 6 7 8 9 10
  13. export class TodoListComponent { items = input<Todo[]>([]) doneItems = input<Todo[]>([])

    markAsDone = output<Todo>(); moveToDone(item: Todo) { this.markAsDone.emit(item); } } 1 2 3 4 5 6 7 8 9 10 items = input<Todo[]>([]) doneItems = input<Todo[]>([]) export class TodoListComponent { 1 2 3 4 markAsDone = output<Todo>(); 5 6 moveToDone(item: Todo) { 7 this.markAsDone.emit(item); 8 } 9 } 10
  14. export class TodoListComponent { items = input<Todo[]>([]) doneItems = input<Todo[]>([])

    markAsDone = output<Todo>(); moveToDone(item: Todo) { this.markAsDone.emit(item); } } 1 2 3 4 5 6 7 8 9 10 items = input<Todo[]>([]) doneItems = input<Todo[]>([]) export class TodoListComponent { 1 2 3 4 markAsDone = output<Todo>(); 5 6 moveToDone(item: Todo) { 7 this.markAsDone.emit(item); 8 } 9 } 10 markAsDone = output<Todo>(); this.markAsDone.emit(item); export class TodoListComponent { 1 items = input<Todo[]>([]) 2 doneItems = input<Todo[]>([]) 3 4 5 6 moveToDone(item: Todo) { 7 8 } 9 } 10
  15. export class TodoListComponent { // Don't do this here //

    It's presentational! private service = inject(Service); items = input<Todo[]>([]) doneItems = input<Todo[]>([]) moveToDone(item: Todo) { this.service. ... } } 1 2 3 4 5 6 7 8 9 10 11 12
  16. export class TodoListComponent { // Don't do this here //

    It's presentational! private service = inject(Service); items = input<Todo[]>([]) doneItems = input<Todo[]>([]) moveToDone(item: Todo) { this.service. ... } } 1 2 3 4 5 6 7 8 9 10 11 12 // Don't do this here // It's presentational! private service = inject(Service); this.service. ... export class TodoListComponent { 1 2 3 4 5 items = input<Todo[]>([]) 6 doneItems = input<Todo[]>([]) 7 8 moveToDone(item: Todo) { 9 10 } 11 } 12
  17. @Component({ selector: 'app-my-doggos', standalone: true, templateUrl: './my-doggos.component.html', styleUrls: ['./my-doggos.component.css'], imports:

    [AsyncPipe, RouterLink, DatePipe, DecimalPipe, NgFor], }) export class MyDoggosComponent implements OnInit { private readonly store = inject(Store); doggos = this.store.select(getMyDoggos); ngOnInit(): void { this.store.dispatch(DoggosActions.loadMyDoggos()); } deleteDoggo(doggo: Doggo) { this.store.dispatch(DoggosActions.deleteDoggo({ doggo })); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
  18. @Component({ selector: 'app-my-doggos', standalone: true, templateUrl: './my-doggos.component.html', styleUrls: ['./my-doggos.component.css'], imports:

    [AsyncPipe, RouterLink, DatePipe, DecimalPipe, NgFor], }) export class MyDoggosComponent implements OnInit { private readonly store = inject(Store); doggos = this.store.select(getMyDoggos); ngOnInit(): void { this.store.dispatch(DoggosActions.loadMyDoggos()); } deleteDoggo(doggo: Doggo) { this.store.dispatch(DoggosActions.deleteDoggo({ doggo })); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
  19. @Component({ selector: 'app-my-doggos', standalone: true, templateUrl: './my-doggos.component.html', styleUrls: ['./my-doggos.component.css'], imports:

    [AsyncPipe, RouterLink, DatePipe, DecimalPipe, NgFor], }) export class MyDoggosComponent implements OnInit { private readonly store = inject(Store); doggos = this.store.selectSignal(getMyDoggos); ngOnInit(): void { this.store.dispatch(DoggosActions.loadMyDoggos()); } deleteDoggo(doggo: Doggo) { this.store.dispatch(DoggosActions.deleteDoggo({ doggo })); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
  20. @Component({ selector: 'app-my-doggos', standalone: true, templateUrl: './my-doggos.component.html', styleUrls: ['./my-doggos.component.css'], imports:

    [AsyncPipe, RouterLink, DatePipe, DecimalPipe, NgFor], }) export class MyDoggosComponent implements OnInit { private readonly store = inject(Store); doggos = this.store.selectSignal(getMyDoggos); ngOnInit(): void { this.store.dispatch(DoggosActions.loadMyDoggos()); } deleteDoggo(doggo: Doggo) { this.store.dispatch(DoggosActions.deleteDoggo({ doggo })); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 doggos = this.store.selectSignal(getMyDoggos); @Component({ 1 selector: 'app-my-doggos', 2 standalone: true, 3 templateUrl: './my-doggos.component.html', 4 styleUrls: ['./my-doggos.component.css'], 5 imports: [AsyncPipe, RouterLink, DatePipe, DecimalPipe, NgFor], 6 }) 7 export class MyDoggosComponent implements OnInit { 8 private readonly store = inject(Store); 9 10 11 12 ngOnInit(): void { 13 this.store.dispatch(DoggosActions.loadMyDoggos()); 14 } 15 16 deleteDoggo(doggo: Doggo) { 17 this.store.dispatch(DoggosActions.deleteDoggo({ doggo })); 18 } 19 } 20
  21. @Injectable() export class TodoEffects { private readonly actions$ = inject(Actions);

    private readonly todoService = inject(TodoService); loadTodos$ = createEffect(() => this.actions$.pipe( ofType(TodoActions.loadAllTodos), concatMap(() => this.todoService.getItems().pipe( map((todos) => TodoActions.loadAllTodosFinished({ todos })), catchError((error) => of(error)) ) ) ) ); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
  22. @Injectable() export class TodoEffects { private readonly actions$ = inject(Actions);

    private readonly todoService = inject(TodoService); loadTodos$ = createEffect(() => this.actions$.pipe( ofType(TodoActions.loadAllTodos), concatMap(() => this.todoService.getItems().pipe( map((todos) => TodoActions.loadAllTodosFinished({ todos })), catchError((error) => of(error)) ) ) ) ); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 this.todoService.getItems().pipe( @Injectable() 1 export class TodoEffects { 2 private readonly actions$ = inject(Actions); 3 4 private readonly todoService = inject(TodoService); 5 6 loadTodos$ = createEffect(() => 7 this.actions$.pipe( 8 ofType(TodoActions.loadAllTodos), 9 concatMap(() => 10 11 map((todos) => TodoActions.loadAllTodosFinished({ todos })), 12 catchError((error) => of(error)) 13 ) 14 ) 15 ) 16 ); 17 } 18
  23. export interface TodoState { items: Todo[]; loading: boolean; } export

    const initialState: TodoState = { items: [], loading: false, }; export const TodoStore = signalStore( withState(initialState), ); 1 2 3 4 5 6 7 8 9 10 11 12 13
  24. export interface TodoState { items: Todo[]; loading: boolean; } export

    const initialState: TodoState = { items: [], loading: false, }; export const TodoStore = signalStore( withState(initialState), ); 1 2 3 4 5 6 7 8 9 10 11 12 13 export interface TodoState { items: Todo[]; loading: boolean; } 1 2 3 4 5 export const initialState: TodoState = { 6 items: [], 7 loading: false, 8 }; 9 10 export const TodoStore = signalStore( 11 withState(initialState), 12 ); 13
  25. export interface TodoState { items: Todo[]; loading: boolean; } export

    const initialState: TodoState = { items: [], loading: false, }; export const TodoStore = signalStore( withState(initialState), ); 1 2 3 4 5 6 7 8 9 10 11 12 13 export interface TodoState { items: Todo[]; loading: boolean; } 1 2 3 4 5 export const initialState: TodoState = { 6 items: [], 7 loading: false, 8 }; 9 10 export const TodoStore = signalStore( 11 withState(initialState), 12 ); 13 export const initialState: TodoState = { items: [], loading: false, }; export interface TodoState { 1 items: Todo[]; 2 loading: boolean; 3 } 4 5 6 7 8 9 10 export const TodoStore = signalStore( 11 withState(initialState), 12 ); 13
  26. export interface TodoState { items: Todo[]; loading: boolean; } export

    const initialState: TodoState = { items: [], loading: false, }; export const TodoStore = signalStore( withState(initialState), ); 1 2 3 4 5 6 7 8 9 10 11 12 13 export interface TodoState { items: Todo[]; loading: boolean; } 1 2 3 4 5 export const initialState: TodoState = { 6 items: [], 7 loading: false, 8 }; 9 10 export const TodoStore = signalStore( 11 withState(initialState), 12 ); 13 export const initialState: TodoState = { items: [], loading: false, }; export interface TodoState { 1 items: Todo[]; 2 loading: boolean; 3 } 4 5 6 7 8 9 10 export const TodoStore = signalStore( 11 withState(initialState), 12 ); 13 export const TodoStore = signalStore( withState(initialState), ); export interface TodoState { 1 items: Todo[]; 2 loading: boolean; 3 } 4 5 export const initialState: TodoState = { 6 items: [], 7 loading: false, 8 }; 9 10 11 12 13
  27. export const TodoStore = signalStore( withState({ /* ... */ }),

    withMethods((...) => ({ // ... })) ); 1 2 3 4 5 6
  28. export const TodoStore = signalStore( withState({ /* ... */ }),

    withMethods((...) => ({ // ... })) ); 1 2 3 4 5 6 withMethods((...) => ({ // ... })) export const TodoStore = signalStore( 1 withState({ /* ... */ }), 2 3 4 5 ); 6
  29. export const TodoStore = signalStore( withState({ /* ... */ ),

    withMethods((store, todoService = inject(TodoService)) => ({ loadAllTodos() { // use Todoservice and then patchState(store, { items }); }, })) ); 1 2 3 4 5 6 7 8 9
  30. export const TodoStore = signalStore( withState({ /* ... */ ),

    withMethods((store, todoService = inject(TodoService)) => ({ loadAllTodos() { // use Todoservice and then patchState(store, { items }); }, })) ); 1 2 3 4 5 6 7 8 9 withMethods((store, todoService = inject(TodoService)) => ({ loadAllTodos() { // use Todoservice and then patchState(store, { items }); }, })) export const TodoStore = signalStore( 1 withState({ /* ... */ ), 2 3 4 5 6 7 8 ); 9
  31. export const TodoStore = signalStore( { providedIn: 'root' }, withState({

    /* state goes here */ ), withMethods((store, todoService = inject(TodoService)) => ({ loadAllTodos: rxMethod( switchMap(() => { patchState(store, {loading: true}); return todoService.getItems().pipe( tapResponse({ next: (items) => patchState(store, {items}), error: console.error, finalize: () => patchState(store, {loading: false}), }) ); }) ), })) ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
  32. export const TodoStore = signalStore( { providedIn: 'root' }, withState({

    /* state goes here */ ), withMethods((store, todoService = inject(TodoService)) => ({ loadAllTodos: rxMethod( switchMap(() => { patchState(store, {loading: true}); return todoService.getItems().pipe( tapResponse({ next: (items) => patchState(store, {items}), error: console.error, finalize: () => patchState(store, {loading: false}), }) ); }) ), })) ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 loadAllTodos: rxMethod( switchMap(() => { patchState(store, {loading: true}); return todoService.getItems().pipe( tapResponse({ next: (items) => patchState(store, {items}), error: console.error, finalize: () => patchState(store, {loading: false}), }) ); }) ), export const TodoStore = signalStore( 1 { providedIn: 'root' }, 2 withState({ /* state goes here */ ), 3 withMethods((store, todoService = inject(TodoService)) => ({ 4 5 6 7 8 9 10 11 12 13 14 15 16 17 })) 18 ); 19
  33. export const TodoStore = signalStore( { providedIn: 'root' }, withState({

    /* state goes here */ ), withMethods((store, todoService = inject(TodoService)) => ({ loadAllTodos: rxMethod( switchMap(() => { patchState(store, {loading: true}); return todoService.getItems().pipe( tapResponse({ next: (items) => patchState(store, {items}), error: console.error, finalize: () => patchState(store, {loading: false}), }) ); }) ), })) ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 loadAllTodos: rxMethod( switchMap(() => { patchState(store, {loading: true}); return todoService.getItems().pipe( tapResponse({ next: (items) => patchState(store, {items}), error: console.error, finalize: () => patchState(store, {loading: false}), }) ); }) ), export const TodoStore = signalStore( 1 { providedIn: 'root' }, 2 withState({ /* state goes here */ ), 3 withMethods((store, todoService = inject(TodoService)) => ({ 4 5 6 7 8 9 10 11 12 13 14 15 16 17 })) 18 ); 19 patchState(store, {loading: true}); export const TodoStore = signalStore( 1 { providedIn: 'root' }, 2 withState({ /* state goes here */ ), 3 withMethods((store, todoService = inject(TodoService)) => ({ 4 loadAllTodos: rxMethod( 5 switchMap(() => { 6 7 8 return todoService.getItems().pipe( 9 tapResponse({ 10 next: (items) => patchState(store, {items}), 11 error: console.error, 12 finalize: () => patchState(store, {loading: false}), 13 }) 14 ); 15 }) 16 ), 17 })) 18 ); 19
  34. export const TodoStore = signalStore( { providedIn: 'root' }, withState({

    /* state goes here */ ), withMethods((store, todoService = inject(TodoService)) => ({ loadAllTodos: rxMethod( switchMap(() => { patchState(store, {loading: true}); return todoService.getItems().pipe( tapResponse({ next: (items) => patchState(store, {items}), error: console.error, finalize: () => patchState(store, {loading: false}), }) ); }) ), })) ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 loadAllTodos: rxMethod( switchMap(() => { patchState(store, {loading: true}); return todoService.getItems().pipe( tapResponse({ next: (items) => patchState(store, {items}), error: console.error, finalize: () => patchState(store, {loading: false}), }) ); }) ), export const TodoStore = signalStore( 1 { providedIn: 'root' }, 2 withState({ /* state goes here */ ), 3 withMethods((store, todoService = inject(TodoService)) => ({ 4 5 6 7 8 9 10 11 12 13 14 15 16 17 })) 18 ); 19 patchState(store, {loading: true}); export const TodoStore = signalStore( 1 { providedIn: 'root' }, 2 withState({ /* state goes here */ ), 3 withMethods((store, todoService = inject(TodoService)) => ({ 4 loadAllTodos: rxMethod( 5 switchMap(() => { 6 7 8 return todoService.getItems().pipe( 9 tapResponse({ 10 next: (items) => patchState(store, {items}), 11 error: console.error, 12 finalize: () => patchState(store, {loading: false}), 13 }) 14 ); 15 }) 16 ), 17 })) 18 ); 19 return todoService.getItems().pipe( tapResponse({ next: (items) => patchState(store, {items}), error: console.error, finalize: () => patchState(store, {loading: false}), }) ); export const TodoStore = signalStore( 1 { providedIn: 'root' }, 2 withState({ /* state goes here */ ), 3 withMethods((store, todoService = inject(TodoService)) => ({ 4 loadAllTodos: rxMethod( 5 switchMap(() => { 6 patchState(store, {loading: true}); 7 8 9 10 11 12 13 14 15 }) 16 ), 17 })) 18 ); 19
  35. export const TodoStore = signalStore( { providedIn: 'root' }, withState({

    /* state goes here */ ), withMethods((store, todoService = inject(TodoService)) => ({ loadAllTodos: rxMethod( switchMap(() => { patchState(store, {loading: true}); return todoService.getItems().pipe( tapResponse({ next: (items) => patchState(store, {items}), error: console.error, finalize: () => patchState(store, {loading: false}), }) ); }) ), })) ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 loadAllTodos: rxMethod( switchMap(() => { patchState(store, {loading: true}); return todoService.getItems().pipe( tapResponse({ next: (items) => patchState(store, {items}), error: console.error, finalize: () => patchState(store, {loading: false}), }) ); }) ), export const TodoStore = signalStore( 1 { providedIn: 'root' }, 2 withState({ /* state goes here */ ), 3 withMethods((store, todoService = inject(TodoService)) => ({ 4 5 6 7 8 9 10 11 12 13 14 15 16 17 })) 18 ); 19 patchState(store, {loading: true}); export const TodoStore = signalStore( 1 { providedIn: 'root' }, 2 withState({ /* state goes here */ ), 3 withMethods((store, todoService = inject(TodoService)) => ({ 4 loadAllTodos: rxMethod( 5 switchMap(() => { 6 7 8 return todoService.getItems().pipe( 9 tapResponse({ 10 next: (items) => patchState(store, {items}), 11 error: console.error, 12 finalize: () => patchState(store, {loading: false}), 13 }) 14 ); 15 }) 16 ), 17 })) 18 ); 19 return todoService.getItems().pipe( tapResponse({ next: (items) => patchState(store, {items}), error: console.error, finalize: () => patchState(store, {loading: false}), }) ); export const TodoStore = signalStore( 1 { providedIn: 'root' }, 2 withState({ /* state goes here */ ), 3 withMethods((store, todoService = inject(TodoService)) => ({ 4 loadAllTodos: rxMethod( 5 switchMap(() => { 6 patchState(store, {loading: true}); 7 8 9 10 11 12 13 14 15 }) 16 ), 17 })) 18 ); 19 tapResponse({ next: (items) => patchState(store, {items}), error: console.error, finalize: () => patchState(store, {loading: false}), }) export const TodoStore = signalStore( 1 { providedIn: 'root' }, 2 withState({ /* state goes here */ ), 3 withMethods((store, todoService = inject(TodoService)) => ({ 4 loadAllTodos: rxMethod( 5 switchMap(() => { 6 patchState(store, {loading: true}); 7 8 return todoService.getItems().pipe( 9 10 11 12 13 14 ); 15 }) 16 ), 17 })) 18 ); 19
  36. export const TodoStore = signalStore( { providedIn: 'root' }, withState({

    /* state goes here */ ), withMethods((store, todoService = inject(TodoService)) => ({ loadAllTodos(store, todoService: TodoService) { ... }, async loadAllTodosByPromise() { patchState(store, { loading: true }); const items = await todoService.getItemsAsPromise(); patchState(store, { items, loading: false }); }, })) ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
  37. export const TodoStore = signalStore( { providedIn: 'root' }, withState({

    /* state goes here */ ), withMethods((store, todoService = inject(TodoService)) => ({ loadAllTodos(store, todoService: TodoService) { ... }, async loadAllTodosByPromise() { patchState(store, { loading: true }); const items = await todoService.getItemsAsPromise(); patchState(store, { items, loading: false }); }, })) ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 async loadAllTodosByPromise() { patchState(store, { loading: true }); const items = await todoService.getItemsAsPromise(); patchState(store, { items, loading: false }); }, export const TodoStore = signalStore( 1 { providedIn: 'root' }, 2 withState({ /* state goes here */ ), 3 withMethods((store, todoService = inject(TodoService)) => ({ 4 loadAllTodos(store, todoService: TodoService) { ... }, 5 6 7 8 9 10 11 12 13 })) 14 ); 15
  38. @Component({ // ... }) export class AppComponent implements OnInit {

    readonly store = inject(TodoStore); ngOnInit() { this.store.loadAllTodos(); } } 1 2 3 4 5 6 7 8 9 10
  39. @Component({ // ... }) export class AppComponent implements OnInit {

    readonly store = inject(TodoStore); ngOnInit() { this.store.loadAllTodos(); } } 1 2 3 4 5 6 7 8 9 10 readonly store = inject(TodoStore); @Component({ 1 // ... 2 }) 3 export class AppComponent implements OnInit { 4 5 6 ngOnInit() { 7 this.store.loadAllTodos(); 8 } 9 } 10
  40. @Component({ // ... }) export class AppComponent implements OnInit {

    readonly store = inject(TodoStore); ngOnInit() { this.store.loadAllTodos(); } } 1 2 3 4 5 6 7 8 9 10 readonly store = inject(TodoStore); @Component({ 1 // ... 2 }) 3 export class AppComponent implements OnInit { 4 5 6 ngOnInit() { 7 this.store.loadAllTodos(); 8 } 9 } 10 this.store.loadAllTodos(); @Component({ 1 // ... 2 }) 3 export class AppComponent implements OnInit { 4 readonly store = inject(TodoStore); 5 6 ngOnInit() { 7 8 } 9 } 10
  41. template: `{{ store.items() }} {{ store.loading() }}`, readonly store =

    inject(TodoStore); @Component({ 1 // ... 2 3 }) 4 export class AppComponent implements OnInit { 5 6 7 ngOnInit() { 8 this.store.loadAllTodos(); 9 } 10 } 11
  42. template: `{{ store.items() }} {{ store.loading() }}`, readonly store =

    inject(TodoStore); @Component({ 1 // ... 2 3 }) 4 export class AppComponent implements OnInit { 5 6 7 ngOnInit() { 8 this.store.loadAllTodos(); 9 } 10 } 11 @Component({ // ... template: `{{ store.items() }} {{ store.loading() }}`, }) export class AppComponent implements OnInit { readonly store = inject(TodoStore); ngOnInit() { this.store.loadAllTodos(); } } 1 2 3 4 5 6 7 8 9 10 11
  43. export const TodoStore = signalStore( { providedIn: 'root' }, withState(initialState),

    withMethods(/* ... */), withHooks({ onInit({ loadAllTodos }) { loadAllTodos(); }, onDestroy() { console.log('on destroy'); }, }) ); 1 2 3 4 5 6 7 8 9 10 11 12 13
  44. export const TodoStore = signalStore( { providedIn: 'root' }, withState(initialState),

    withMethods(/* ... */), withHooks({ onInit({ loadAllTodos }) { loadAllTodos(); }, onDestroy() { console.log('on destroy'); }, }) ); 1 2 3 4 5 6 7 8 9 10 11 12 13 withHooks({ onInit({ loadAllTodos }) { loadAllTodos(); }, onDestroy() { console.log('on destroy'); }, }) export const TodoStore = signalStore( 1 { providedIn: 'root' }, 2 withState(initialState), 3 withMethods(/* ... */), 4 5 6 7 8 9 10 11 12 ); 13
  45. @Component({ // ... }) export class AppComponent implements OnInit {

    readonly store = inject(TodoStore); ngOnInit() { this.store.loadAllTodos(); } } 1 2 3 4 5 6 7 8 9 10
  46. @Component({ // ... }) export class AppComponent { readonly store

    = inject(TodoStore); // No Logic !!! Yay!!! } 1 2 3 4 5 6 7 8
  47. export const TodoStore = signalStore( withState(initialState), withComputed(({ items }) =>

    ({ doneCount: computed(() => items().filter((x) => x.done).length), undoneCount: computed(() => items().filter((x) => !x.done).length), percentageDone: computed(() => { const done = items().filter((x) => x.done).length; const total = items().length; if (total === 0) { return 0; } return (done / total) * 100; }), })), withMethods(/* ... */), withHooks(/* ... */) ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
  48. export const TodoStore = signalStore( withState(initialState), withComputed(({ items }) =>

    ({ doneCount: computed(() => items().filter((x) => x.done).length), undoneCount: computed(() => items().filter((x) => !x.done).length), percentageDone: computed(() => { const done = items().filter((x) => x.done).length; const total = items().length; if (total === 0) { return 0; } return (done / total) * 100; }), })), withMethods(/* ... */), withHooks(/* ... */) ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 withComputed(({ items }) => ({ doneCount: computed(() => items().filter((x) => x.done).length), undoneCount: computed(() => items().filter((x) => !x.done).length), percentageDone: computed(() => { const done = items().filter((x) => x.done).length; const total = items().length; if (total === 0) { return 0; } return (done / total) * 100; }), })), export const TodoStore = signalStore( 1 withState(initialState), 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 withMethods(/* ... */), 19 withHooks(/* ... */) 20 ); 21
  49. export const TodoStore = signalStore( withState(initialState), withComputed(({ items }) =>

    ({ doneCount: computed(() => items().filter((x) => x.done).length), undoneCount: computed(() => items().filter((x) => !x.done).length), percentageDone: computed(() => { const done = items().filter((x) => x.done).length; const total = items().length; if (total === 0) { return 0; } return (done / total) * 100; }), })), withMethods(/* ... */), withHooks(/* ... */) ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 withComputed(({ items }) => ({ doneCount: computed(() => items().filter((x) => x.done).length), undoneCount: computed(() => items().filter((x) => !x.done).length), percentageDone: computed(() => { const done = items().filter((x) => x.done).length; const total = items().length; if (total === 0) { return 0; } return (done / total) * 100; }), })), export const TodoStore = signalStore( 1 withState(initialState), 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 withMethods(/* ... */), 19 withHooks(/* ... */) 20 ); 21 doneCount: computed(() => items().filter((x) => x.done).length), export const TodoStore = signalStore( 1 withState(initialState), 2 3 withComputed(({ items }) => ({ 4 5 undoneCount: computed(() => items().filter((x) => !x.done).length), 6 percentageDone: computed(() => { 7 const done = items().filter((x) => x.done).length; 8 const total = items().length; 9 10 if (total === 0) { 11 return 0; 12 } 13 14 return (done / total) * 100; 15 }), 16 })), 17 18 withMethods(/* ... */), 19 withHooks(/* ... */) 20 ); 21
  50. export const TodoStore = signalStore( withState(initialState), withComputed(({ items }) =>

    ({ doneCount: computed(() => items().filter((x) => x.done).length), undoneCount: computed(() => items().filter((x) => !x.done).length), percentageDone: computed(() => { const done = items().filter((x) => x.done).length; const total = items().length; if (total === 0) { return 0; } return (done / total) * 100; }), })), withMethods(/* ... */), withHooks(/* ... */) ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 withComputed(({ items }) => ({ doneCount: computed(() => items().filter((x) => x.done).length), undoneCount: computed(() => items().filter((x) => !x.done).length), percentageDone: computed(() => { const done = items().filter((x) => x.done).length; const total = items().length; if (total === 0) { return 0; } return (done / total) * 100; }), })), export const TodoStore = signalStore( 1 withState(initialState), 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 withMethods(/* ... */), 19 withHooks(/* ... */) 20 ); 21 doneCount: computed(() => items().filter((x) => x.done).length), export const TodoStore = signalStore( 1 withState(initialState), 2 3 withComputed(({ items }) => ({ 4 5 undoneCount: computed(() => items().filter((x) => !x.done).length), 6 percentageDone: computed(() => { 7 const done = items().filter((x) => x.done).length; 8 const total = items().length; 9 10 if (total === 0) { 11 return 0; 12 } 13 14 return (done / total) * 100; 15 }), 16 })), 17 18 withMethods(/* ... */), 19 withHooks(/* ... */) 20 ); 21 undoneCount: computed(() => items().filter((x) => !x.done).length), export const TodoStore = signalStore( 1 withState(initialState), 2 3 withComputed(({ items }) => ({ 4 doneCount: computed(() => items().filter((x) => x.done).length), 5 6 percentageDone: computed(() => { 7 const done = items().filter((x) => x.done).length; 8 const total = items().length; 9 10 if (total === 0) { 11 return 0; 12 } 13 14 return (done / total) * 100; 15 }), 16 })), 17 18 withMethods(/* ... */), 19 withHooks(/* ... */) 20 ); 21
  51. export const TodoStore = signalStore( withState(initialState), withComputed(({ items }) =>

    ({ doneCount: computed(() => items().filter((x) => x.done).length), undoneCount: computed(() => items().filter((x) => !x.done).length), percentageDone: computed(() => { const done = items().filter((x) => x.done).length; const total = items().length; if (total === 0) { return 0; } return (done / total) * 100; }), })), withMethods(/* ... */), withHooks(/* ... */) ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 withComputed(({ items }) => ({ doneCount: computed(() => items().filter((x) => x.done).length), undoneCount: computed(() => items().filter((x) => !x.done).length), percentageDone: computed(() => { const done = items().filter((x) => x.done).length; const total = items().length; if (total === 0) { return 0; } return (done / total) * 100; }), })), export const TodoStore = signalStore( 1 withState(initialState), 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 withMethods(/* ... */), 19 withHooks(/* ... */) 20 ); 21 doneCount: computed(() => items().filter((x) => x.done).length), export const TodoStore = signalStore( 1 withState(initialState), 2 3 withComputed(({ items }) => ({ 4 5 undoneCount: computed(() => items().filter((x) => !x.done).length), 6 percentageDone: computed(() => { 7 const done = items().filter((x) => x.done).length; 8 const total = items().length; 9 10 if (total === 0) { 11 return 0; 12 } 13 14 return (done / total) * 100; 15 }), 16 })), 17 18 withMethods(/* ... */), 19 withHooks(/* ... */) 20 ); 21 undoneCount: computed(() => items().filter((x) => !x.done).length), export const TodoStore = signalStore( 1 withState(initialState), 2 3 withComputed(({ items }) => ({ 4 doneCount: computed(() => items().filter((x) => x.done).length), 5 6 percentageDone: computed(() => { 7 const done = items().filter((x) => x.done).length; 8 const total = items().length; 9 10 if (total === 0) { 11 return 0; 12 } 13 14 return (done / total) * 100; 15 }), 16 })), 17 18 withMethods(/* ... */), 19 withHooks(/* ... */) 20 ); 21 percentageDone: computed(() => { const done = items().filter((x) => x.done).length; const total = items().length; if (total === 0) { return 0; } return (done / total) * 100; }), export const TodoStore = signalStore( 1 withState(initialState), 2 3 withComputed(({ items }) => ({ 4 doneCount: computed(() => items().filter((x) => x.done).length), 5 undoneCount: computed(() => items().filter((x) => !x.done).length), 6 7 8 9 10 11 12 13 14 15 16 })), 17 18 withMethods(/* ... */), 19 withHooks(/* ... */) 20 ); 21
  52. @Component({ providers: [TodoStore], templates: ` <div> {{ store.doneCount() }} /

    {{ store.undoneCount() }} {{ store.percentageDone() }} </div> ` }) export class AppComponent implements OnInit { readonly store = inject(TodoStore); } 1 2 3 4 5 6 7 8 9 10 11
  53. @Component({ providers: [TodoStore], templates: ` <div> {{ store.doneCount() }} /

    {{ store.undoneCount() }} {{ store.percentageDone() }} </div> ` }) export class AppComponent implements OnInit { readonly store = inject(TodoStore); } 1 2 3 4 5 6 7 8 9 10 11 <div> {{ store.doneCount() }} / {{ store.undoneCount() }} {{ store.percentageDone() }} </div> ` @Component({ 1 providers: [TodoStore], 2 templates: ` 3 4 5 6 7 }) 8 export class AppComponent implements OnInit { 9 readonly store = inject(TodoStore); 10 } 11
  54. src/ |-- feature-a | |-- container | |-- presentational |

    |-- services | `-- ... |-- feature-b | `-- ... `-- shared |-- services `-- ... 1 2 3 4 5 6 7 8 9 10 11
  55. { providedIn: 'root' }, export const DoggosStore = signalStore( 1

    2 withState<DoggoState>(initialState), 3 withComputed((store, authStore = inject(AuthStore)) => ()), 4 withMethods( 5 ( ... ) => ({ 6 // Methods 7 }) 8 ), 9 withHooks() 10 ); 11
  56. { providedIn: 'root' }, export const DoggosStore = signalStore( 1

    2 withState<DoggoState>(initialState), 3 withComputed((store, authStore = inject(AuthStore)) => ()), 4 withMethods( 5 ( ... ) => ({ 6 // Methods 7 }) 8 ), 9 withHooks() 10 ); 11 withComputed((store, authStore = inject(AuthStore)) => ()), export const DoggosStore = signalStore( 1 { providedIn: 'root' }, 2 withState<DoggoState>(initialState), 3 4 withMethods( 5 ( ... ) => ({ 6 // Methods 7 }) 8 ), 9 withHooks() 10 ); 11
  57. export type ConnectionStatus = 'On' | 'Off' | 'Reconnecting' |

    'Not Set'; 1 2 export interface RealTimeState { 3 connectionStatus: ConnectionStatus; 4 } 5 6 export const initialState: RealTimeState = { 7 connectionStatus: 'Not Set', 8 }; 9 10 export const RealTimeStore = signalStore( 11 { providedIn: 'root' }, 12 withState<RealTimeState>(initialState), 13 withMethods((store) => ({ 14 setConnectionStatus: rxMethod<ConnectionStatus>( 15 tap((connectionStatus: ConnectionStatus) => 16 patchState(store, { connectionStatus }) 17 ) 18 ), 19 })), 20 withHooks({ 21 onInit( 22 { setConnectionStatus }, 23 signalRStatusService = inject(SignalRStatusService) 24 ) { 25 setConnectionStatus(signalRStatusService.connectionStatus$); 26 }, 27 }) 28 ); 29
  58. export type ConnectionStatus = 'On' | 'Off' | 'Reconnecting' |

    'Not Set'; 1 2 export interface RealTimeState { 3 connectionStatus: ConnectionStatus; 4 } 5 6 export const initialState: RealTimeState = { 7 connectionStatus: 'Not Set', 8 }; 9 10 export const RealTimeStore = signalStore( 11 { providedIn: 'root' }, 12 withState<RealTimeState>(initialState), 13 withMethods((store) => ({ 14 setConnectionStatus: rxMethod<ConnectionStatus>( 15 tap((connectionStatus: ConnectionStatus) => 16 patchState(store, { connectionStatus }) 17 ) 18 ), 19 })), 20 withHooks({ 21 onInit( 22 { setConnectionStatus }, 23 signalRStatusService = inject(SignalRStatusService) 24 ) { 25 setConnectionStatus(signalRStatusService.connectionStatus$); 26 }, 27 }) 28 ); 29 export interface RealTimeState { connectionStatus: ConnectionStatus; } export const initialState: RealTimeState = { connectionStatus: 'Not Set', }; export type ConnectionStatus = 'On' | 'Off' | 'Reconnecting' | 'Not Set'; 1 2 3 4 5 6 7 8 9 10 export const RealTimeStore = signalStore( 11 { providedIn: 'root' }, 12 withState<RealTimeState>(initialState), 13 withMethods((store) => ({ 14 setConnectionStatus: rxMethod<ConnectionStatus>( 15 tap((connectionStatus: ConnectionStatus) => 16 patchState(store, { connectionStatus }) 17 ) 18 ), 19 })), 20 withHooks({ 21 onInit( 22 { setConnectionStatus }, 23 signalRStatusService = inject(SignalRStatusService) 24 ) { 25 setConnectionStatus(signalRStatusService.connectionStatus$); 26 }, 27 }) 28 ); 29
  59. export type ConnectionStatus = 'On' | 'Off' | 'Reconnecting' |

    'Not Set'; 1 2 export interface RealTimeState { 3 connectionStatus: ConnectionStatus; 4 } 5 6 export const initialState: RealTimeState = { 7 connectionStatus: 'Not Set', 8 }; 9 10 export const RealTimeStore = signalStore( 11 { providedIn: 'root' }, 12 withState<RealTimeState>(initialState), 13 withMethods((store) => ({ 14 setConnectionStatus: rxMethod<ConnectionStatus>( 15 tap((connectionStatus: ConnectionStatus) => 16 patchState(store, { connectionStatus }) 17 ) 18 ), 19 })), 20 withHooks({ 21 onInit( 22 { setConnectionStatus }, 23 signalRStatusService = inject(SignalRStatusService) 24 ) { 25 setConnectionStatus(signalRStatusService.connectionStatus$); 26 }, 27 }) 28 ); 29 export interface RealTimeState { connectionStatus: ConnectionStatus; } export const initialState: RealTimeState = { connectionStatus: 'Not Set', }; export type ConnectionStatus = 'On' | 'Off' | 'Reconnecting' | 'Not Set'; 1 2 3 4 5 6 7 8 9 10 export const RealTimeStore = signalStore( 11 { providedIn: 'root' }, 12 withState<RealTimeState>(initialState), 13 withMethods((store) => ({ 14 setConnectionStatus: rxMethod<ConnectionStatus>( 15 tap((connectionStatus: ConnectionStatus) => 16 patchState(store, { connectionStatus }) 17 ) 18 ), 19 })), 20 withHooks({ 21 onInit( 22 { setConnectionStatus }, 23 signalRStatusService = inject(SignalRStatusService) 24 ) { 25 setConnectionStatus(signalRStatusService.connectionStatus$); 26 }, 27 }) 28 ); 29 export const RealTimeStore = signalStore( { providedIn: 'root' }, withState<RealTimeState>(initialState), withMethods((store) => ({ setConnectionStatus: rxMethod<ConnectionStatus>( tap((connectionStatus: ConnectionStatus) => patchState(store, { connectionStatus }) ) ), })), withHooks({ onInit( { setConnectionStatus }, signalRStatusService = inject(SignalRStatusService) ) { setConnectionStatus(signalRStatusService.connectionStatus$); }, }) ); export type ConnectionStatus = 'On' | 'Off' | 'Reconnecting' | 'Not Set'; 1 2 export interface RealTimeState { 3 connectionStatus: ConnectionStatus; 4 } 5 6 export const initialState: RealTimeState = { 7 connectionStatus: 'Not Set', 8 }; 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
  60. export type ConnectionStatus = 'On' | 'Off' | 'Reconnecting' |

    'Not Set'; 1 2 export interface RealTimeState { 3 connectionStatus: ConnectionStatus; 4 } 5 6 export const initialState: RealTimeState = { 7 connectionStatus: 'Not Set', 8 }; 9 10 export const RealTimeStore = signalStore( 11 { providedIn: 'root' }, 12 withState<RealTimeState>(initialState), 13 withMethods((store) => ({ 14 setConnectionStatus: rxMethod<ConnectionStatus>( 15 tap((connectionStatus: ConnectionStatus) => 16 patchState(store, { connectionStatus }) 17 ) 18 ), 19 })), 20 withHooks({ 21 onInit( 22 { setConnectionStatus }, 23 signalRStatusService = inject(SignalRStatusService) 24 ) { 25 setConnectionStatus(signalRStatusService.connectionStatus$); 26 }, 27 }) 28 ); 29 export interface RealTimeState { connectionStatus: ConnectionStatus; } export const initialState: RealTimeState = { connectionStatus: 'Not Set', }; export type ConnectionStatus = 'On' | 'Off' | 'Reconnecting' | 'Not Set'; 1 2 3 4 5 6 7 8 9 10 export const RealTimeStore = signalStore( 11 { providedIn: 'root' }, 12 withState<RealTimeState>(initialState), 13 withMethods((store) => ({ 14 setConnectionStatus: rxMethod<ConnectionStatus>( 15 tap((connectionStatus: ConnectionStatus) => 16 patchState(store, { connectionStatus }) 17 ) 18 ), 19 })), 20 withHooks({ 21 onInit( 22 { setConnectionStatus }, 23 signalRStatusService = inject(SignalRStatusService) 24 ) { 25 setConnectionStatus(signalRStatusService.connectionStatus$); 26 }, 27 }) 28 ); 29 export const RealTimeStore = signalStore( { providedIn: 'root' }, withState<RealTimeState>(initialState), withMethods((store) => ({ setConnectionStatus: rxMethod<ConnectionStatus>( tap((connectionStatus: ConnectionStatus) => patchState(store, { connectionStatus }) ) ), })), withHooks({ onInit( { setConnectionStatus }, signalRStatusService = inject(SignalRStatusService) ) { setConnectionStatus(signalRStatusService.connectionStatus$); }, }) ); export type ConnectionStatus = 'On' | 'Off' | 'Reconnecting' | 'Not Set'; 1 2 export interface RealTimeState { 3 connectionStatus: ConnectionStatus; 4 } 5 6 export const initialState: RealTimeState = { 7 connectionStatus: 'Not Set', 8 }; 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 export type ConnectionStatus = 'On' | 'Off' | 'Reconnecting' | 'Not Set'; export interface RealTimeState { connectionStatus: ConnectionStatus; } export const initialState: RealTimeState = { connectionStatus: 'Not Set', }; export const RealTimeStore = signalStore( { providedIn: 'root' }, withState<RealTimeState>(initialState), withMethods((store) => ({ setConnectionStatus: rxMethod<ConnectionStatus>( tap((connectionStatus: ConnectionStatus) => patchState(store, { connectionStatus }) ) ), })), withHooks({ onInit( { setConnectionStatus }, signalRStatusService = inject(SignalRStatusService) ) { setConnectionStatus(signalRStatusService.connectionStatus$); }, }) ); 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
  61. { providedIn: 'root' }, export const DoggosStore = signalStore( 1

    2 withState<DoggoState>(initialState), 3 withComputed((store, authStore = inject(AuthStore)) => ({ /* ... */ })), 4 withMethods( 5 () => ({ 6 startListeningToRealtimeDoggoEvents() { 7 signalRService.start(); 8 }, 9 10 stopListeningToRealtimeDoggoEvents() { 11 signalRService.stop(); 12 }, 13 rateDoggoFromRealTime: rxMethod<Doggo>( /* ... */ ), 14 addDoggoFromRealTime: rxMethod<Doggo>(rxMethod<Doggo>( /* ... */ )), 15 deleteDoggoFromRealTime: rxMethod<string>( /* ... */ ), 16 }) 17 ), 18 withHooks({ 19 onInit(store, signalRService = inject(SignalRService)) { 20 const addedDoggo$ = signalRService.doggoEvents.pipe( 21 filter( 22 (event): event is DoggoAddedEvent => event.type === 'doggoadded' 23 ), 24 map(({ doggo }) => doggo) 25 ); 26 const deletedDoggoId$ = signalRService.doggoEvents.pipe( 27 filter( 28 (event): event is DoggoDeletedEvent => event.type === 'doggodeleted' 29 ), 30 map(({ id }) => id) 31 ); 32 const ratedDoggo$ = signalRService.doggoEvents.pipe( 33 filter( 34 (event): event is DoggoRatedEvent => event.type === 'doggorated' 35
  62. { providedIn: 'root' }, export const DoggosStore = signalStore( 1

    2 withState<DoggoState>(initialState), 3 withComputed((store, authStore = inject(AuthStore)) => ({ /* ... */ })), 4 withMethods( 5 () => ({ 6 startListeningToRealtimeDoggoEvents() { 7 signalRService.start(); 8 }, 9 10 stopListeningToRealtimeDoggoEvents() { 11 signalRService.stop(); 12 }, 13 rateDoggoFromRealTime: rxMethod<Doggo>( /* ... */ ), 14 addDoggoFromRealTime: rxMethod<Doggo>(rxMethod<Doggo>( /* ... */ )), 15 deleteDoggoFromRealTime: rxMethod<string>( /* ... */ ), 16 }) 17 ), 18 withHooks({ 19 onInit(store, signalRService = inject(SignalRService)) { 20 const addedDoggo$ = signalRService.doggoEvents.pipe( 21 filter( 22 (event): event is DoggoAddedEvent => event.type === 'doggoadded' 23 ), 24 map(({ doggo }) => doggo) 25 ); 26 const deletedDoggoId$ = signalRService.doggoEvents.pipe( 27 filter( 28 (event): event is DoggoDeletedEvent => event.type === 'doggodeleted' 29 ), 30 map(({ id }) => id) 31 ); 32 const ratedDoggo$ = signalRService.doggoEvents.pipe( 33 filter( 34 (event): event is DoggoRatedEvent => event.type === 'doggorated' 35 withMethods( () => ({ startListeningToRealtimeDoggoEvents() { signalRService.start(); }, stopListeningToRealtimeDoggoEvents() { signalRService.stop(); }, rateDoggoFromRealTime: rxMethod<Doggo>( /* ... */ ), addDoggoFromRealTime: rxMethod<Doggo>(rxMethod<Doggo>( /* ... */ )), deleteDoggoFromRealTime: rxMethod<string>( /* ... */ ), }) ), export const DoggosStore = signalStore( 1 { providedIn: 'root' }, 2 withState<DoggoState>(initialState), 3 withComputed((store, authStore = inject(AuthStore)) => ({ /* ... */ })), 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 withHooks({ 19 onInit(store, signalRService = inject(SignalRService)) { 20 const addedDoggo$ = signalRService.doggoEvents.pipe( 21 filter( 22 (event): event is DoggoAddedEvent => event.type === 'doggoadded' 23 ), 24 map(({ doggo }) => doggo) 25 ); 26 const deletedDoggoId$ = signalRService.doggoEvents.pipe( 27 filter( 28 (event): event is DoggoDeletedEvent => event.type === 'doggodeleted' 29 ), 30 map(({ id }) => id) 31 ); 32 const ratedDoggo$ = signalRService.doggoEvents.pipe( 33 filter( 34 (event): event is DoggoRatedEvent => event.type === 'doggorated' 35
  63. { providedIn: 'root' }, export const DoggosStore = signalStore( 1

    2 withState<DoggoState>(initialState), 3 withComputed((store, authStore = inject(AuthStore)) => ({ /* ... */ })), 4 withMethods( 5 () => ({ 6 startListeningToRealtimeDoggoEvents() { 7 signalRService.start(); 8 }, 9 10 stopListeningToRealtimeDoggoEvents() { 11 signalRService.stop(); 12 }, 13 rateDoggoFromRealTime: rxMethod<Doggo>( /* ... */ ), 14 addDoggoFromRealTime: rxMethod<Doggo>(rxMethod<Doggo>( /* ... */ )), 15 deleteDoggoFromRealTime: rxMethod<string>( /* ... */ ), 16 }) 17 ), 18 withHooks({ 19 onInit(store, signalRService = inject(SignalRService)) { 20 const addedDoggo$ = signalRService.doggoEvents.pipe( 21 filter( 22 (event): event is DoggoAddedEvent => event.type === 'doggoadded' 23 ), 24 map(({ doggo }) => doggo) 25 ); 26 const deletedDoggoId$ = signalRService.doggoEvents.pipe( 27 filter( 28 (event): event is DoggoDeletedEvent => event.type === 'doggodeleted' 29 ), 30 map(({ id }) => id) 31 ); 32 const ratedDoggo$ = signalRService.doggoEvents.pipe( 33 filter( 34 (event): event is DoggoRatedEvent => event.type === 'doggorated' 35 withMethods( () => ({ startListeningToRealtimeDoggoEvents() { signalRService.start(); }, stopListeningToRealtimeDoggoEvents() { signalRService.stop(); }, rateDoggoFromRealTime: rxMethod<Doggo>( /* ... */ ), addDoggoFromRealTime: rxMethod<Doggo>(rxMethod<Doggo>( /* ... */ )), deleteDoggoFromRealTime: rxMethod<string>( /* ... */ ), }) ), export const DoggosStore = signalStore( 1 { providedIn: 'root' }, 2 withState<DoggoState>(initialState), 3 withComputed((store, authStore = inject(AuthStore)) => ({ /* ... */ })), 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 withHooks({ 19 onInit(store, signalRService = inject(SignalRService)) { 20 const addedDoggo$ = signalRService.doggoEvents.pipe( 21 filter( 22 (event): event is DoggoAddedEvent => event.type === 'doggoadded' 23 ), 24 map(({ doggo }) => doggo) 25 ); 26 const deletedDoggoId$ = signalRService.doggoEvents.pipe( 27 filter( 28 (event): event is DoggoDeletedEvent => event.type === 'doggodeleted' 29 ), 30 map(({ id }) => id) 31 ); 32 const ratedDoggo$ = signalRService.doggoEvents.pipe( 33 filter( 34 (event): event is DoggoRatedEvent => event.type === 'doggorated' 35 startListeningToRealtimeDoggoEvents() { signalRService.start(); }, stopListeningToRealtimeDoggoEvents() { signalRService.stop(); }, rateDoggoFromRealTime: rxMethod<Doggo>( /* ... */ ), addDoggoFromRealTime: rxMethod<Doggo>(rxMethod<Doggo>( /* ... */ )), deleteDoggoFromRealTime: rxMethod<string>( /* ... */ ), export const DoggosStore = signalStore( 1 { providedIn: 'root' }, 2 withState<DoggoState>(initialState), 3 withComputed((store, authStore = inject(AuthStore)) => ({ /* ... */ })), 4 withMethods( 5 () => ({ 6 7 8 9 10 11 12 13 14 15 16 }) 17 ), 18 withHooks({ 19 onInit(store, signalRService = inject(SignalRService)) { 20 const addedDoggo$ = signalRService.doggoEvents.pipe( 21 filter( 22 (event): event is DoggoAddedEvent => event.type === 'doggoadded' 23 ), 24 map(({ doggo }) => doggo) 25 ); 26 const deletedDoggoId$ = signalRService.doggoEvents.pipe( 27 filter( 28 (event): event is DoggoDeletedEvent => event.type === 'doggodeleted' 29 ), 30 map(({ id }) => id) 31 ); 32 const ratedDoggo$ = signalRService.doggoEvents.pipe( 33 filter( 34 (event): event is DoggoRatedEvent => event.type === 'doggorated' 35
  64. { providedIn: 'root' }, export const DoggosStore = signalStore( 1

    2 withState<DoggoState>(initialState), 3 withComputed((store, authStore = inject(AuthStore)) => ({ /* ... */ })), 4 withMethods( 5 () => ({ 6 startListeningToRealtimeDoggoEvents() { 7 signalRService.start(); 8 }, 9 10 stopListeningToRealtimeDoggoEvents() { 11 signalRService.stop(); 12 }, 13 rateDoggoFromRealTime: rxMethod<Doggo>( /* ... */ ), 14 addDoggoFromRealTime: rxMethod<Doggo>(rxMethod<Doggo>( /* ... */ )), 15 deleteDoggoFromRealTime: rxMethod<string>( /* ... */ ), 16 }) 17 ), 18 withHooks({ 19 onInit(store, signalRService = inject(SignalRService)) { 20 const addedDoggo$ = signalRService.doggoEvents.pipe( 21 filter( 22 (event): event is DoggoAddedEvent => event.type === 'doggoadded' 23 ), 24 map(({ doggo }) => doggo) 25 ); 26 const deletedDoggoId$ = signalRService.doggoEvents.pipe( 27 filter( 28 (event): event is DoggoDeletedEvent => event.type === 'doggodeleted' 29 ), 30 map(({ id }) => id) 31 ); 32 const ratedDoggo$ = signalRService.doggoEvents.pipe( 33 filter( 34 (event): event is DoggoRatedEvent => event.type === 'doggorated' 35 withMethods( () => ({ startListeningToRealtimeDoggoEvents() { signalRService.start(); }, stopListeningToRealtimeDoggoEvents() { signalRService.stop(); }, rateDoggoFromRealTime: rxMethod<Doggo>( /* ... */ ), addDoggoFromRealTime: rxMethod<Doggo>(rxMethod<Doggo>( /* ... */ )), deleteDoggoFromRealTime: rxMethod<string>( /* ... */ ), }) ), export const DoggosStore = signalStore( 1 { providedIn: 'root' }, 2 withState<DoggoState>(initialState), 3 withComputed((store, authStore = inject(AuthStore)) => ({ /* ... */ })), 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 withHooks({ 19 onInit(store, signalRService = inject(SignalRService)) { 20 const addedDoggo$ = signalRService.doggoEvents.pipe( 21 filter( 22 (event): event is DoggoAddedEvent => event.type === 'doggoadded' 23 ), 24 map(({ doggo }) => doggo) 25 ); 26 const deletedDoggoId$ = signalRService.doggoEvents.pipe( 27 filter( 28 (event): event is DoggoDeletedEvent => event.type === 'doggodeleted' 29 ), 30 map(({ id }) => id) 31 ); 32 const ratedDoggo$ = signalRService.doggoEvents.pipe( 33 filter( 34 (event): event is DoggoRatedEvent => event.type === 'doggorated' 35 startListeningToRealtimeDoggoEvents() { signalRService.start(); }, stopListeningToRealtimeDoggoEvents() { signalRService.stop(); }, rateDoggoFromRealTime: rxMethod<Doggo>( /* ... */ ), addDoggoFromRealTime: rxMethod<Doggo>(rxMethod<Doggo>( /* ... */ )), deleteDoggoFromRealTime: rxMethod<string>( /* ... */ ), export const DoggosStore = signalStore( 1 { providedIn: 'root' }, 2 withState<DoggoState>(initialState), 3 withComputed((store, authStore = inject(AuthStore)) => ({ /* ... */ })), 4 withMethods( 5 () => ({ 6 7 8 9 10 11 12 13 14 15 16 }) 17 ), 18 withHooks({ 19 onInit(store, signalRService = inject(SignalRService)) { 20 const addedDoggo$ = signalRService.doggoEvents.pipe( 21 filter( 22 (event): event is DoggoAddedEvent => event.type === 'doggoadded' 23 ), 24 map(({ doggo }) => doggo) 25 ); 26 const deletedDoggoId$ = signalRService.doggoEvents.pipe( 27 filter( 28 (event): event is DoggoDeletedEvent => event.type === 'doggodeleted' 29 ), 30 map(({ id }) => id) 31 ); 32 const ratedDoggo$ = signalRService.doggoEvents.pipe( 33 filter( 34 (event): event is DoggoRatedEvent => event.type === 'doggorated' 35 onInit(store, signalRService = inject(SignalRService)) { const addedDoggo$ = signalRService.doggoEvents.pipe( filter( (event): event is DoggoAddedEvent => event.type === 'doggoadded' ), map(({ doggo }) => doggo) ); const deletedDoggoId$ = signalRService.doggoEvents.pipe( filter( (event): event is DoggoDeletedEvent => event.type === 'doggodeleted' ), map(({ id }) => id) ); const ratedDoggo$ = signalRService.doggoEvents.pipe( filter( (event): event is DoggoRatedEvent => event.type === 'doggorated' ), map(({ doggo }) => doggo) ); store.addDoggoFromRealTime(addedDoggo$); store.rateDoggoFromRealTime(ratedDoggo$); store.deleteDoggoFromRealTime(deletedDoggoId$); }, }, 9 10 stopListeningToRealtimeDoggoEvents() { 11 signalRService.stop(); 12 }, 13 rateDoggoFromRealTime: rxMethod<Doggo>( /* ... */ ), 14 addDoggoFromRealTime: rxMethod<Doggo>(rxMethod<Doggo>( /* ... */ )), 15 deleteDoggoFromRealTime: rxMethod<string>( /* ... */ ), 16 }) 17 ), 18 withHooks({ 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 }) 44 ); 45
  65. // my.store.ts const MyStore = signalStore( withMethods((store, myService = inject(MyService))

    => ({ doSomething() { myService.doSomething2(); }, }) ); 1 2 3 4 5 6 7 8 9 // my.store.spec.ts 10 beforeEach(() => { 11 TestBed.configureTestingModule({ 12 providers: [ 13 MyStore, 14 { provide: MyService, useValue: { doSomething2: jest.fn() } } 15 ], 16 }); 17 }); 18 19 it('works', () => { 20 const myStore = TestBed.inject(MyStore); 21 const myService = TestBed.inject(MyService); 22 23 myStore.doSomething(); 24 25 expect(myService.doSomething2).toHaveBeenCalled(); 26 }); 27
  66. // my.store.ts const MyStore = signalStore( withMethods((store, myService = inject(MyService))

    => ({ doSomething() { myService.doSomething2(); }, }) ); 1 2 3 4 5 6 7 8 9 // my.store.spec.ts 10 beforeEach(() => { 11 TestBed.configureTestingModule({ 12 providers: [ 13 MyStore, 14 { provide: MyService, useValue: { doSomething2: jest.fn() } } 15 ], 16 }); 17 }); 18 19 it('works', () => { 20 const myStore = TestBed.inject(MyStore); 21 const myService = TestBed.inject(MyService); 22 23 myStore.doSomething(); 24 25 expect(myService.doSomething2).toHaveBeenCalled(); 26 }); 27 // my.store.spec.ts beforeEach(() => { TestBed.configureTestingModule({ providers: [ MyStore, { provide: MyService, useValue: { doSomething2: jest.fn() } } ], }); }); // my.store.ts 1 const MyStore = signalStore( 2 withMethods((store, myService = inject(MyService)) => ({ 3 doSomething() { 4 myService.doSomething2(); 5 }, 6 }) 7 ); 8 9 10 11 12 13 14 15 16 17 18 19 it('works', () => { 20 const myStore = TestBed.inject(MyStore); 21 const myService = TestBed.inject(MyService); 22 23 myStore.doSomething(); 24 25 expect(myService.doSomething2).toHaveBeenCalled(); 26 }); 27
  67. // my.store.ts const MyStore = signalStore( withMethods((store, myService = inject(MyService))

    => ({ doSomething() { myService.doSomething2(); }, }) ); 1 2 3 4 5 6 7 8 9 // my.store.spec.ts 10 beforeEach(() => { 11 TestBed.configureTestingModule({ 12 providers: [ 13 MyStore, 14 { provide: MyService, useValue: { doSomething2: jest.fn() } } 15 ], 16 }); 17 }); 18 19 it('works', () => { 20 const myStore = TestBed.inject(MyStore); 21 const myService = TestBed.inject(MyService); 22 23 myStore.doSomething(); 24 25 expect(myService.doSomething2).toHaveBeenCalled(); 26 }); 27 // my.store.spec.ts beforeEach(() => { TestBed.configureTestingModule({ providers: [ MyStore, { provide: MyService, useValue: { doSomething2: jest.fn() } } ], }); }); // my.store.ts 1 const MyStore = signalStore( 2 withMethods((store, myService = inject(MyService)) => ({ 3 doSomething() { 4 myService.doSomething2(); 5 }, 6 }) 7 ); 8 9 10 11 12 13 14 15 16 17 18 19 it('works', () => { 20 const myStore = TestBed.inject(MyStore); 21 const myService = TestBed.inject(MyService); 22 23 myStore.doSomething(); 24 25 expect(myService.doSomething2).toHaveBeenCalled(); 26 }); 27 it('works', () => { const myStore = TestBed.inject(MyStore); const myService = TestBed.inject(MyService); myStore.doSomething(); expect(myService.doSomething2).toHaveBeenCalled(); }); // my.store.ts 1 const MyStore = signalStore( 2 withMethods((store, myService = inject(MyService)) => ({ 3 doSomething() { 4 myService.doSomething2(); 5 }, 6 }) 7 ); 8 9 // my.store.spec.ts 10 beforeEach(() => { 11 TestBed.configureTestingModule({ 12 providers: [ 13 MyStore, 14 { provide: MyService, useValue: { doSomething2: jest.fn() } } 15 ], 16 }); 17 }); 18 19 20 21 22 23 24 25 26 27