From 4cfed2361302c85043ab46a803df2333be6d777d Mon Sep 17 00:00:00 2001 From: Florian THIERRY Date: Sat, 5 Mar 2022 12:36:59 +0100 Subject: [PATCH] Add description saving and silent save in service. --- .../task-display/task-display.component.html | 2 +- .../task-display/task-display.component.ts | 44 ++++++- src/app/core/service/task-list.service.ts | 113 +++++++++++------- 3 files changed, 112 insertions(+), 47 deletions(-) diff --git a/src/app/active-list-tasks/task-display/task-display.component.html b/src/app/active-list-tasks/task-display/task-display.component.html index f4bc947..76ae368 100644 --- a/src/app/active-list-tasks/task-display/task-display.component.html +++ b/src/app/active-list-tasks/task-display/task-display.component.html @@ -16,7 +16,7 @@ - +
diff --git a/src/app/active-list-tasks/task-display/task-display.component.ts b/src/app/active-list-tasks/task-display/task-display.component.ts index d857eff..f2be344 100644 --- a/src/app/active-list-tasks/task-display/task-display.component.ts +++ b/src/app/active-list-tasks/task-display/task-display.component.ts @@ -1,5 +1,7 @@ -import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnInit, Output, ViewChild } from '@angular/core'; +import { AfterViewInit, Component, ElementRef, EventEmitter, Input, OnDestroy, OnInit, Output, ViewChild } from '@angular/core'; import { FormControl } from '@angular/forms'; +import { Subscription } from 'rxjs'; +import { debounceTime, distinctUntilChanged } from 'rxjs/operators'; import { Task } from 'src/app/core/entity/task'; import { TaskListService } from 'src/app/core/service/task-list.service'; @@ -9,11 +11,14 @@ import { TaskListService } from 'src/app/core/service/task-list.service'; templateUrl: './task-display.component.html', styleUrls: ['./task-display.component.scss'] }) -export class TaskDisplayComponent implements AfterViewInit { +export class TaskDisplayComponent implements AfterViewInit, OnDestroy { @Input() task?: Task; - titleControl = new FormControl(this.task?.title); - isExpanded = false; @ViewChild('titleInput', {static: true}) titleInput?: ElementRef; + @ViewChild('descriptionInput', {static: true}) descriptionInput?: ElementRef; + titleControl = new FormControl(); + descriptionControl = new FormControl(); + isExpanded = false; + private _subscriptions: Subscription[] = []; constructor( private _taskListService: TaskListService @@ -21,6 +26,37 @@ export class TaskDisplayComponent implements AfterViewInit { ngAfterViewInit(): void { this.titleControl.setValue(this?.task?.title); + this.descriptionControl.setValue(this?.task?.description); + + const titleControlSubscription = this.titleControl.valueChanges + .pipe( + distinctUntilChanged(), + debounceTime(500) + ) + .subscribe(newTitle => { + if (this.task) { + this.task.title = newTitle; + this._taskListService.updateTask(this.task); + } + }); + this._subscriptions.push(titleControlSubscription); + + const descriptionControlSubscription = this.descriptionControl.valueChanges + .pipe( + distinctUntilChanged(), + debounceTime(500) + ) + .subscribe(description => { + if (this.task) { + this.task.description = description; + this._taskListService.updateTask(this.task); + } + }); + this._subscriptions.push(descriptionControlSubscription); + } + + ngOnDestroy(): void { + this._subscriptions.forEach(subscription => subscription.unsubscribe()); } expand(): void { diff --git a/src/app/core/service/task-list.service.ts b/src/app/core/service/task-list.service.ts index 629272c..9f433b5 100644 --- a/src/app/core/service/task-list.service.ts +++ b/src/app/core/service/task-list.service.ts @@ -13,49 +13,78 @@ import { Router } from "@angular/router"; }) export class TaskListService { private _store: BehaviorSubject = new BehaviorSubject(undefined as unknown as Store); - + constructor( private _router: Router, private _storePersistenceService: StorePersistenceService - ) { - this.store$.subscribe(store => { - this._storePersistenceService.save(store); - }); - } - - get store$(): Observable { - return this._store.asObservable() - .pipe(filter(store => !!store)); - } - - private get store(): Store { - return this._storePersistenceService.load(); - } - - addTask(taskTitle: string): void { - const store = this.store; - const activeTaskList = store.taskLists.find(taskList => taskList.id === store.activeTaskListId); - if (!activeTaskList) { - throw new Error("No active tasklist"); + ) { + this.store$.subscribe(store => { + this.saveStore(store, true); + }); + } + + get store$(): Observable { + return this._store.asObservable() + .pipe(filter(store => !!store)); + } + + private get store(): Store { + return this._storePersistenceService.load(); } - if (!activeTaskList.tasks) { - activeTaskList.tasks = []; + private saveStore(store: Store, silent: boolean = false): void { + if (silent) { + this._storePersistenceService.save(store); + } else { + // We send the store into the subject because there is an observable on in, that saves the store at every single value. + this._store.next(store); + } } + + addTask(taskTitle: string): void { + const store = this.store; + const activeTaskList = store.taskLists.find(taskList => taskList.id === store.activeTaskListId); + if (!activeTaskList) { + throw new Error("No active tasklist"); + } + + if (!activeTaskList.tasks) { + activeTaskList.tasks = []; + } + + const newTask = { + id: uuidv4(), + title: taskTitle, + creationDate: new Date(), + description: undefined as unknown as string + } as Task; + + + activeTaskList?.tasks.push(newTask); + this.saveStore(store); + } + + updateTask(taskToUpdate: Task) { + const store = this.store; + const activeTaskList = store.taskLists.find(taskList => taskList.id === store.activeTaskListId); + if (!activeTaskList) { + throw new Error("No active tasklist"); + } - const newTask = { - id: uuidv4(), - title: taskTitle, - creationDate: new Date(), - description: undefined as unknown as string - } as Task; + const task = activeTaskList?.tasks.find(task => task.id === taskToUpdate.id); + if (!task) { + throw new Error('Unknown task to update'); + } + task.title = taskToUpdate.title; + task.description = taskToUpdate.description; - activeTaskList?.tasks.push(newTask); - this._store.next(store); - } - - delete(taskToDelete: Task) { + // If the store is saved loudly, all views will be refreshed and the user will lose the focus of its input, + // so we save the store silently here. + this.saveStore(store, true); + } + + delete(taskToDelete: Task) { const store = this.store; const activeTaskList = store.taskLists.find(taskList => taskList.id === store.activeTaskListId); if (!activeTaskList) { @@ -68,7 +97,7 @@ export class TaskListService { } activeTaskList?.tasks.splice(taskIndex, 1); - this._store.next(store); + this.saveStore(store); } createTaskList(taskListName: string): void { @@ -80,7 +109,7 @@ export class TaskListService { const store = this.store; store.taskLists.push(newTaskList); - this._store.next(store); + this.saveStore(store); } getAll(): TaskList[] { @@ -90,14 +119,14 @@ export class TaskListService { setActive(taskList: TaskList): void { const store = this.store; store.activeTaskListId = taskList.id; - this._store.next(store); + this.saveStore(store); this._router.navigate(['/task-lists/active']); } removeActiveTaskList(): void { const store = this.store; delete store.activeTaskListId; - this._store.next(store); + this.saveStore(store); this._router.navigate(['/']); } @@ -118,10 +147,10 @@ export class TaskListService { store.selectionMode = false; } - this._store.next(store); + this.saveStore(store); } else { store.selectedTaskLists.push(taskList); - this._store.next(store); + this.saveStore(store); } } @@ -137,13 +166,13 @@ export class TaskListService { enableSelectionMode(): void { const store = this.store; store.selectionMode = true; - this._store.next(store); + this.saveStore(store); } disableSelectionMode(): void { const store = this.store; store.selectionMode = false; store.selectedTaskLists = []; - this._store.next(store); + this.saveStore(store); } }