I have been trying to develop a todo list project. I have four components : Daily, Item-List, Item and Add-task dailog
The daily component holds a form and a list that displays the values from form. What I am looking to do next is to have a form in a dialog modal(new separate component) and add its value to the list in the daily component
Below are the codes:
Daily.service.ts
This service code is used to get the value from the form and add it to the list.
import { Injectable } from '@angular/core';
import { BehaviorSubject, Observable } from 'rxjs';
import { DailyTask } from './models';
@Injectable({ providedIn: 'root' })
export class DailyService {
private _dailies$ = new BehaviorSubject<DailyTask[]>([]);
public getDailies(): DailyTask[] {
return this._dailies$.getValue();
}
public setDailies(data: DailyTask[]): void {
this._dailies$.next(data);
}
public getDailiesObservable(): Observable<DailyTask[]> {
return this._dailies$.asObservable();
}
public createTask(newTask: string): void{
console.log( "check");
const dailyTask: DailyTask = { task: newTask, type: 'DAILY' };
this.setDailies([dailyTask, ...this.getDailies()])
}
}
Daily.component.Ts
export class DailyComponent implements OnInit {
public dailyList$: Observable<DailyTask[]> | null = null;
constructor(private _dailyService: DailyService) {}
ngOnInit(): void {
this.dailyList$ = this._dailyService.getDailiesObservable();
}
public addDaily(name: string) {
this._dailyService.createTask(name);
}
}
Daily.component.html
<mat-card>
<h1>Daily</h1>
<app-item-list
[type]="'DAILY'"
[initialData$]="dailyList$"
[onAddItem]="addDaily.bind(this)"
></app-item-list>
</mat-card>
Item-List.component.html
<div>
<mat-form-field appearance="outline">
<input
matInput
placeholder="Add a Task"
(keyup.enter)="addTask()"
autocomplete="off"
[formControl]="nameControl"/>
</mat-form-field>
</div>
<ng-container *ngIf="filteredData$ | async as data">
<app-item
[value]="value"
*ngFor="let value of data; index as index"
(inputDataChange)="removeTask(data, index)"
>
</app-item>
</ng-container>
Item-list.component.ts
export class ItemListComponent implements OnInit {
nameControl = new FormControl('');
@Input() public type: ItemType | null = null;
@Input() public onAddItem: Function | null = null;
constructor(private _homeService: HomeService) {}
ngOnInit(): void {}
addTask() {
if (this.onAddItem) {
this.onAddItem(this.nameControl.value);
this.nameControl.reset();
}
}
item.component.html
<div >
<div [ngClass]="{ 'line-through': value.task }">
{{ value.task | uppercase }}
</div>
</div>
item.component.ts
export class ItemComponent implements OnInit {
@Input()
value: any;
constructor() {}
ngOnInit(): void {}
}
The above set of codes works perfect, below the code for new component task-dailog
task-dailog.html
<div mat-dialog-title >
<h1 >Create Daily</h1>
</div>
<div mat-dialog-content>
<div >
<p>Task</p>
<mat-form-field appearance="outline">
<input
matInput
placeholder="Add a new Task"
autocomplete="off"
(keyup.enter)="addDailogTask()"
[formControl]="nameControl"
/>
</mat-form-field>
</div>
</div>
task-dailog.component.ts
export class TaskDialogComponent implements OnInit {
nameControl = new FormControl('');
constructor(
public dialogRef: MatDialogRef<TaskDialogComponent>,
private _dailyService: DailyService,
) {}
ngOnInit(): void {}
onNoClick(): void {
this.dialogRef.close();
}
addDailogTask(){
const value$ = this.nameControl.value;
this.nameControl.reset();
console.log(value$);
}
}
Here in the task-dialog.component.ts, I have the function to get the value from the form, but I am stuck here and dont know how to proceed. I would like to learn how to send this form value from TaskDialogComponent to the list inside DailyComponent.
Here is also the Stackblitz for the project.
Can someone help me with this . I am relatively new to angular and would really appreciate the help. Thanks in advance!.
CodePudding user response:
this._dailyService.createTask(value$);
could be called from anywhere as long you use the same service instance.
this will trigger this.dailyList$
the observable and update the list too.
export class TaskDialogComponent implements OnInit {
nameControl = new FormControl('');
@Input() public onAddDialogItem: Function | null = null;
constructor(
public dialogRef: MatDialogRef<TaskDialogComponent>,
private _dailyService: DailyService,
) {}
ngOnInit(): void {}
onNoClick(): void {
this.dialogRef.close();
}
addDailogTask(){
const value$ = this.nameControl.value;
// you can add it from the service
this._dailyService.createTask(value$);
this.nameControl.reset();
console.log(value$);
}
}
CodePudding user response:
You need to cast your form value type first, By default form.value
can be return as any
that isn't match createTask
function that require only string
Solution
addDailogTask() {
const value$ = this.nameControl.value as string;
...
}
CodePudding user response:
So basically you can get the value from the dialog in the afterClosed().subscribe
method.
add-task-btn.component.ts:
@Component({
selector: 'app-add-task-btn',
templateUrl: './add-task-btn.component.html',
styleUrls: ['./add-task-btn.component.scss'],
})
export class AddTaskBtnComponent implements OnInit {
...
dialogRef.afterClosed().subscribe((result) => {
if (result) {
this.dailyService.setDailies(`${result}`); // <--<< you can get the value returned from the dialog here.
} else {
console.log('The dialog was closed');
}
});
}
}
But I see a major problem with your code and how it is structured.
You want to structure your code in the same way as how your UI is structured. So it would be easier to work with. for example:
src app L home L components L ProfileBar L SearchBar L add-task-btn L ... L services L models L home.component.ts L home.component.scss L home.component.html
Not sure why you decided to put each component in a separate module. Which is unnecessary technically the login page could be in one module and everything else that is in the homecomponent could be in another module. That way you can lazyload the
HomeModule
. Also you have to import theDailyModule
in other modules just to useDailyService
.When you have a deeply nested component. I would recommend to use a state management library (I use ngxs) its a lot easier to work with so you don't have to pass values through the
@input
decorator. Also it would make your code a lot more readable.