1. This site uses cookies. By continuing to use this site, you are agreeing to our use of cookies. Learn More.
  2. Anuncie Aqui
    Anuncie aqui você Também: fdantas@4each.com.br

Issue with Populating Modal Form for Editing Tasks in Angular

Discussão em 'Angular' iniciado por Ahmad Sher Khan, Outubro 15, 2024.

  1. I'm working on an Angular application where I have a modal form (FormSubComponent) that is used for both adding new tasks and editing existing ones. When I open the modal for editing a task, the form is not getting populated with the task data, even though the data (with which the modal form is to be populated) is being emitted and handled correctly in other components.

    task-service.service.ts

    import { Injectable } from '@angular/core';
    import { BehaviorSubject, Observable } from 'rxjs';
    import { HttpClient } from '@angular/common/http';
    import { taskType } from './taskType';
    import { tap } from 'rxjs/operators';

    @Injectable({
    providedIn: 'root',
    })
    export class TaskServiceService {
    private url: string = 'http://localhost:3000/tasks';

    private taskSubject = new BehaviorSubject<taskType[]>([]);
    public tasks$ = this.taskSubject.asObservable(); // Expose the observable for task list

    private taskToEditSubject = new BehaviorSubject<taskType>({
    id: '',
    title: '',
    description: '',
    status: ''
    });
    public taskToEdit$ = this.taskToEditSubject.asObservable(); // Expose the observable for task to edit

    constructor(private http: HttpClient) {
    this.fetchTask(); // Fetch initial task list
    }

    // Fetch all tasks from the server
    fetchTask() {
    this.http.get<taskType[]>(this.url).subscribe({
    next: (data: taskType[]) => {
    this.taskSubject.next(data); // Update task list
    },
    error: (error) => {
    this.taskSubject.error(error); // Handle error
    },
    });
    }

    // Add a new task
    addTask(newTask: taskType): Observable<taskType> {
    return this.http.post<taskType>(this.url, newTask).pipe(
    tap((task: taskType) => {
    const updatedTasks = [...this.taskSubject.value, task]; // Update task list
    this.taskSubject.next(updatedTasks);
    })
    );
    }

    // Delete a task by ID
    deleteTask(id: string): Observable<void> {
    return this.http.delete<void>(`${this.url}/${id}`).pipe(
    tap(() => {
    const updatedTasks = this.taskSubject.value.filter(task => task.id !== id); // Update task list
    this.taskSubject.next(updatedTasks);
    })
    );
    }

    // Get a task by ID for editing
    getTaskByID(id: string): Observable<taskType> {
    return this.http.get<taskType>(`${this.url}/${id}`);
    }

    // Update an existing task
    updateTask(task: taskType): Observable<taskType> {
    return this.http.put<taskType>(`${this.url}/${task.id}`, task).pipe(
    tap((updatedTask: taskType) => {
    const index = this.taskSubject.value.findIndex(t => t.id === updatedTask.id);
    if (index !== -1) {
    const updatedTasks = [...this.taskSubject.value];
    updatedTasks[index] = updatedTask; // Update the task in the list
    this.taskSubject.next(updatedTasks); // Emit the updated task list
    }
    })
    );
    }

    // Emit task data for editing
    emitData(task: taskType) {
    this.taskToEditSubject.next(task); // Update the current task to edit
    }
    }


    table-sub.component.ts (Here the task with specific id is fetched and emitted to make it available for form modal component to populate itself with this task)

    import { Component, EventEmitter, OnDestroy, OnInit, Output } from '@angular/core';
    import { TaskServiceService } from '../../task-service.service';
    import { taskType } from '../../taskType';
    import { CommonModule } from '@angular/common';
    import { Subscription } from 'rxjs';
    import { NgbModal } from '@ng-bootstrap/ng-bootstrap';
    import { FormSubComponent } from '../form-sub/form-sub.component';


    @Component({
    selector: 'app-table-sub',
    standalone: true,
    imports: [CommonModule,FormSubComponent],
    templateUrl: './table-sub.component.html',
    styleUrl: './table-sub.component.css',
    providers:[]
    })
    export class TableSubComponent implements OnDestroy {
    AllTasks: taskType[] = [];




    private subscription: Subscription = new Subscription();

    constructor(private taskObj: TaskServiceService,private modalService: NgbModal){
    }
    ngOnDestroy(): void {
    this.subscription.unsubscribe();
    }

    ngOnInit(){
    this.getAllTasks()

    }


    getAllTasks() {
    this.subscription.add(
    this.taskObj.tasks$.subscribe(data => {
    this.AllTasks = data;
    })
    );
    this.taskObj.fetchTask();
    }


    deleteTask(id:string){
    this.taskObj.deleteTask(id).subscribe({
    next: (data)=>{
    console.log('this task is deleted',data)
    }, error: (error)=>{
    console.log(error)
    }
    })
    }

    async onEdit(id:string){
    this.openModal()

    this.taskObj.getTaskByID(id).subscribe((data=>{
    console.log('data to be emitted (Table)', data)
    this.taskObj.emitData(data)
    }))

    }

    openModal(){
    const modalRef = this.modalService.open(FormSubComponent);
    modalRef.componentInstance.title = 'Edit Task';
    }

    }


    table-sub.component.html

    <table class="table table-striped">
    <thead class="thead-dark">
    <tr>
    <th scope="col">#</th>
    <th scope="col">Title</th>
    <th scope="col">Description</th>
    <th scope="col">Status</th>
    <th scope="col">Actions</th>
    </tr>
    </thead>
    <tbody>
    <tr *ngFor="let tasks of AllTasks; index as i ">
    <th scope="row">{{i+1}}</th>
    <td>{{tasks.title}}</td>
    <td>{{tasks.description}}</td>
    <td>{{tasks.status}}</td>
    <td>
    <button class="btn btn-sm btn-primary" (click)="onEdit(tasks.id)" >
    <i class="bi bi-pencil-square" ></i> <!-- Edit Icon -->
    </button>
    <button class="btn btn-sm btn-danger" (click)="deleteTask(tasks.id)">
    <i class="bi bi-trash" ></i>
    </button>
    </td>
    </tr>

    </tbody>
    </table>


    form-sub.component.ts(here the data emitted by table-sub component will be received and form will be populated but its not working as intended, it just opens the form model with no data)

    import { Component } from '@angular/core';
    import { FormControl, FormGroup, ReactiveFormsModule, Validators } from '@angular/forms';
    import { NgbActiveModal } from '@ng-bootstrap/ng-bootstrap';
    import { TaskServiceService } from '../../task-service.service';
    import { taskType } from '../../taskType';
    import { HttpClientModule } from '@angular/common/http';

    @Component({
    selector: 'app-form-sub',
    standalone: true,
    imports: [ReactiveFormsModule],
    templateUrl: './form-sub.component.html',
    styleUrl: './form-sub.component.css',
    providers:[]
    })
    export class FormSubComponent {
    constructor(public activeModal: NgbActiveModal,private taskObj: TaskServiceService) {
    this.formInit()
    }

    myFormGroup!: FormGroup
    valuesToPatch!: taskType
    editMode!: boolean

    ngOnInit(){
    this.taskObj.taskToEdit$.subscribe((task)=>{
    this.valuesToPatch=task
    console.log('values to Patch in form',this.valuesToPatch) // This logs an empty object
    if(this.valuesToPatch){
    this.editMode = true
    this.myFormGroup.patchValue({
    title: this.valuesToPatch.title,
    description: this.valuesToPatch.description,
    status:this.valuesToPatch.status
    })
    }
    })
    }


    formInit(){
    this.myFormGroup = new FormGroup({
    title: new FormControl('',Validators.required),
    description: new FormControl('',Validators.required),
    status: new FormControl('',Validators.required)
    })
    }



    onSubmit(myForm: FormGroup){
    if(myForm.valid){
    if(this.editMode === false){
    this.taskObj.addTask(myForm.value).subscribe({
    next: (data)=>{
    this.taskObj.fetchTask()
    },error:(error)=>{
    console.log("some error occured", error)
    }
    })
    }else if(this.editMode === true){
    this.taskObj.updateTask(myForm.value).subscribe({
    next: (data:taskType)=>{

    }, error:(error)=>{

    }
    })
    }

    }


    }

    onClose() {
    this.activeModal.close('Modal Closed'); // This will close the modal
    }

    onDismiss() {
    this.activeModal.dismiss('Modal Dismissed'); // This will dismiss the modal
    }


    }


    form-sub.component.html

    <div class="modal-dialog">
    <div class="modal-content bg-dark text-white"> <!-- Dark background and white text -->
    <div class="modal-header">
    <h4 class="modal-title" id="modal-basic-title">Add Task</h4>
    <button type="button" class="btn-close" aria-label="Close" (click)="onDismiss()">X</button>
    </div>
    <div class="modal-body">
    <form [formGroup]="myFormGroup" (ngSubmit)="onSubmit(myFormGroup)">
    <label for="title">Title:</label>
    <input id="title" type="text" class="form-control bg-secondary text-white" formControlName="title"> <!-- Dark input field -->

    <label for="description" class="mt-2">Description:</label>
    <input id="description" type="text" class="form-control bg-secondary text-white" formControlName="description"> <!-- Dark input field -->

    <label for="status" class="mt-2">Status:</label>
    <select id="status" class="form-control bg-secondary text-white" formControlName="status">
    <option value="Pending">Pending</option>
    <option value="In Progress">In Progress</option>
    <option value="Completed">Completed</option>
    </select>
    <div class="'button-center"><button type="submit" class="btn btn-primary" >Save changes</button></div>

    </form>
    </div>
    <div class="modal-footer">
    <button type="button" class="btn btn-secondary" (click)="onClose()">Close</button>

    </div>
    </div>
    </div>


    taskType interface

    export interface taskType {
    id: string,
    title: string,
    description: string,
    status: string
    }


    I am trying to update current task in my task list, there is a button associated with each task when clicked should open a form modal with the information of the task populated in it, when the edit button is clicked the data is successfully emitted to service and service is successfully sending data but when I try to subscribe to the emitted data in modal form it shows a blank task object and hence form is not getting populated.

    How can I ensure that the modal form is populated with the existing task data when opened for editing? Is there an issue with the timing of the data emission and the modal opening that could be preventing the form from receiving the data?

    Continue reading...

Compartilhe esta Página