diff --git a/projects/todo-mvc/src/app/todo.component.ts b/projects/todo-mvc/src/app/todo.component.ts index 563d5b1..2bc4406 100644 --- a/projects/todo-mvc/src/app/todo.component.ts +++ b/projects/todo-mvc/src/app/todo.component.ts @@ -11,49 +11,85 @@ import { } from '@angular/core'; import { RxStrategyProvider } from '@rx-angular/cdk/render-strategies'; import { rxState } from '@rx-angular/state'; -import { rxActions } from '@rx-angular/state/actions'; +import { eventValue, rxActions } from '@rx-angular/state/actions'; import { rxEffects } from '@rx-angular/state/effects'; import { select } from '@rx-angular/state/selections'; +import { merge, switchMap, take } from 'rxjs'; import { Todo } from './todo.service'; +interface Actions { + remove: Todo; + toggleDone: boolean; + updateText: string; + edit: void; +} + +interface Transforms { + toggleDone: (e: Event) => boolean; + updateText: (e: Event | string) => string; +} + +const eventChecked = (e: Event): boolean => { + return (e.target as HTMLInputElement).checked; +}; + @Component({ standalone: true, selector: 'app-todo', changeDetection: ChangeDetectionStrategy.OnPush, template: ` @if (isEditing) { + + } @else { +
- } @else { -
- - - -
+ + +
} `, }) export class TodoComponent { private readonly cd = inject(ChangeDetectorRef); private readonly strategyProvider = inject(RxStrategyProvider); + + readonly actions = rxActions(({ transforms }) => + transforms({ + toggleDone: eventChecked, + updateText: eventValue, + }) + ); + private readonly state = rxState<{ isEditing: boolean; todo: Todo }>( - ({ set }) => set({ isEditing: false }) + ({ set, connect }) => { + set({ isEditing: false }); + connect('todo', this.actions.toggleDone$, ({ todo }, done: boolean) => ({ + ...todo, + done, + })); + connect(this.actions.updateText$, ({ todo }, text: string) => ({ + isEditing: false, + todo: { + ...todo, + text, + }, + })); + connect('isEditing', this.actions.edit$, () => true); + } ); - private readonly actions = rxActions<{ remove: Todo; update: Todo }>(); @ViewChild('input') input?: ElementRef; - @ViewChild('toggle') toggle?: ElementRef; @HostBinding('class.todo') readonly hostClass = true; @HostBinding('class.completed') get completed(): boolean { @@ -77,7 +113,10 @@ export class TodoComponent { } @Output() remove = this.actions.remove$; - @Output() update = this.actions.update$; + @Output() update = merge( + this.actions.toggleDone$, + this.actions.updateText$ + ).pipe(switchMap(() => this.state.select('todo').pipe(take(1)))); constructor() { rxEffects(({ register }) => { @@ -97,35 +136,4 @@ export class TodoComponent { register(focusInputWhenEditing$); }); } - - toggleDone(): void { - this.state.set(({ todo }) => ({ - todo: { - ...todo, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - done: this.toggle!.nativeElement.checked, - }, - })); - this.actions.update(this.todo); - } - - edit(): void { - this.state.set({ isEditing: true }); - } - - destroy(): void { - this.actions.remove(this.todo); - } - - updateText(): void { - this.state.set(({ todo }) => ({ - isEditing: false, - todo: { - ...todo, - // eslint-disable-next-line @typescript-eslint/no-non-null-assertion - text: this.input!.nativeElement.value, - }, - })); - this.actions.update(this.todo); - } }