Skip to content
Snippets Groups Projects
Commit bc0920bb authored by thibault.capt's avatar thibault.capt
Browse files

(feat): add todoStore for using ngrx signals store

parent f8213855
No related branches found
No related tags found
No related merge requests found
......@@ -3,7 +3,10 @@
"version": 1,
"cli": {
"packageManager": "pnpm",
"schematicCollections": ["angular-eslint"]
"schematicCollections": [
"angular-eslint"
],
"analytics": false
},
"newProjectRoot": "projects",
"projects": {
......
This diff is collapsed.
......@@ -2,23 +2,24 @@ import { TodoService } from '@core/ports/todo.service';
import { inject } from '@angular/core';
import { HttpService } from '@shared/http.service';
import { Todo, Todos } from '@core/models/todo';
import { Observable } from 'rxjs';
export class HttpTodoService implements TodoService {
private readonly http = inject(HttpService);
getAll() {
getAll(): Observable<Todos> {
return this.http.get<Todos>('todos');
}
add(todoName: string) {
add(todoName: string): Observable<Todo> {
return this.http.post<Todo>('todos', { name: todoName });
}
toggleCompleted(todoId: number) {
toggleCompleted(todoId: number): Observable<Todo> {
return this.http.patch<Todo>(`todos/${todoId}`, {});
}
remove(todoId: number) {
return this.http.delete<void>(`todos/${todoId}`);
remove(todoId: number): Observable<number> {
return this.http.delete<number>(`todos/${todoId}`);
}
}
......@@ -31,8 +31,8 @@ export class InMemoryTodoService implements TodoService {
return of(todo);
}
remove(todoId: number): Observable<void> {
remove(todoId: number): Observable<number> {
this.todos = this.todos.filter((todo) => todo.id !== todoId);
return of(void 0);
return of(todoId);
}
}
import { Todo } from '@core/models/todo';
export class TodoBuilder {
......
......@@ -5,5 +5,5 @@ export abstract class TodoService {
abstract getAll(): Observable<Todos>;
abstract add(todoName: string): Observable<Todo>;
abstract toggleCompleted(todoId: number): Observable<Todo>;
abstract remove(todoId: number): Observable<void>;
abstract remove(todoId: number): Observable<number>;
}
import { patchState, signalStore, withComputed, withHooks, withMethods, withState } from '@ngrx/signals';
import { Todos } from '@core/models/todo';
import { computed, inject } from '@angular/core';
import { TodoService } from '@core/ports/todo.service';
import { rxMethod } from '@ngrx/signals/rxjs-interop';
import { exhaustMap, pipe, switchMap, tap } from 'rxjs';
type TodoState = {
todos: Todos;
loading: boolean;
};
const initialState: TodoState = {
todos: [],
loading: false,
};
export const TodoStore = signalStore(
withState<TodoState>(initialState),
withComputed((store) => ({
isLoading: computed(() => store.loading),
})),
withMethods((store, todoService = inject(TodoService)) => ({
getAll: rxMethod<void>(
pipe(
tap(() => patchState(store, { loading: true })),
switchMap(() => todoService.getAll()),
tap((todos) => patchState(store, { todos, loading: false }))
)
),
add: rxMethod<string>(
pipe(
tap(() => patchState(store, { loading: true })),
exhaustMap((todoName) => todoService.add(todoName)),
tap((todo) => patchState(store, { todos: [...store.todos(), todo], loading: false }))
)
),
remove: rxMethod<number>(
pipe(
tap(() => patchState(store, { loading: true })),
exhaustMap((id) => todoService.remove(id)),
tap((id) => patchState(store, { todos: store.todos().filter((todo) => todo.id !== id), loading: false }))
)
),
toggleCompleted: rxMethod<number>(
pipe(
tap(() => patchState(store, { loading: true })),
exhaustMap((id) => todoService.toggleCompleted(id)),
tap((todo) =>
patchState(store, { todos: store.todos().map((t) => (t.id === todo.id ? todo : t)), loading: false })
)
)
),
})),
withHooks((store) => ({
onInit() {
store.getAll();
},
}))
);
......@@ -6,14 +6,17 @@ import { FormsModule } from '@angular/forms';
import { Todo } from '@core/models/todo';
import { AddTodoFormComponent } from '@features/todo-list/components/add-todo-form.component';
import { TodoListItemComponent } from '@features/todo-list/components/todo-list-item';
import { TodoStore } from '@core/todo.store';
@Component({
selector: 'app-todo-list',
imports: [FormsModule, AddTodoFormComponent, TodoListItemComponent, TodoListItemComponent],
templateUrl: './todo-list.component.html',
changeDetection: ChangeDetectionStrategy.OnPush,
providers: [TodoStore],
})
export default class TodoListComponent {
// TODO: Implement the logic with TodoStore
private reload$$ = new BehaviorSubject<void>(void 0);
private readonly todoService = inject(TodoService);
todos = toSignal(this.reload$$.pipe(switchMap(() => this.todoService.getAll())));
......
export const environment = {
api: {
url: 'http://localhost:8080/api/v1'
}
url: 'http://localhost:8080/api/v1',
},
};
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment