Search code examples
angulartypescriptangular2-changedetection

How to detect change from one component into other


Angular 4. Github source

I have a menu which is filled by a web service. The web service is in taskService, but is not necessary now.

ngOnInit() {
    this.getTasks();
    }
    getTasks(): void {
        this.taskService.getTasks()
            .subscribe(Tasks => this.tasks = Tasks);
    } 

When you click on a task it loads a page, a different component, with a form ready to update the data. It is also made by a web service and works fine. The problem is that after update the task, it is not reflected in the task menu

I am importing this:

import { Component, OnInit, ChangeDetectorRef } from '@angular/core';

and adding this to the constructor:

private cdRef: ChangeDetectorRef

And this is my best approach to the detectChanges() function, after update the data with the save() function

  this.taskService.updateTask(task, id)
          .subscribe(
              this.Ref.detach();
              setInterval(() => {
                this.Ref.detectChanges();
              }, 5000);
      );

This is the html from the menu to print the tasks:

   <li *ngFor="let task of tasks" class="d-inline-block col-md-12">
        <a routerLink="/task/{{task.id}}" > {{task.title}}</a>
        <!-- <span class="close big"></span> -->
        <button class="close big" title="delete task"
        (click)="delete(task)">x</button>
    </li>

And this is the form that updates the task

<form (ngSubmit)="save(taskName.value, taskBody.value)" #taskForm="ngForm" class="example-form">
  <mat-form-field class="example-full-width">
    <label>Task Name</label>
    <input matInput [(ngModel)]="task.name" #taskName name="name">
  </mat-form-field>

  <mat-form-field class="example-full-width">
    <textarea matInput [(ngModel)]="task.body" #taskBody name="body"></textarea>

  </mat-form-field>
  <button type="submit" class="btn btn-success" >Save</button>
</form>

Both are in different components.

I have tried to follow this tutorial, but I'm stuck, I don't know how to use the ChangeDetectorRef.


Solution

  • I've looked at your code. The problem is that the view-task.component updates your tasks, but the navigation.component is not notified about this transaction. I think BehaviorSubject might be just the thing for you.

    You can read more about it here

    I assume you would have single array of tasks throughout your application and you would display them on your navigation component.

    Task.service.ts

    export class TaskService {
         // behaviorSubject needs an initial value.
         private tasks: BehaviorSubject = new BehaviorSubject([]);
         private taskList: Task[];
    
         getTasks() {
             if (!this.taskList || this.taskList.length === 0) {
                 this.initializeTasks();
             }
    
             return this.tasks.asObservable();
         }
    
         initializeTasks() {
              this.http.get('api/tasks')
                  .subscribe(tasks => {
                       // next method will notify all of the subscribers
                       this.tasks.next(tasks);
                  }, error => {
                       // proper error handling here
                  });
         }
    
         updateTasks(task: Task) {
              this.http.post('api/updateTask')
                  .subscribe(resp => {
                       // update your tasks array
                       this.tasks = ...
                       // and call next method of your behaviorSubject with updated list
                       this.tasks.next(this.tasks);
                  }, error => {
                       // proper error handling here    
                  });
         }
    }
    

    Navigation.component.ts

     export class NavigationComponent implements OnInit{
          tasks: Task[];
          constructor(private taskService: TaskService) {}
    
          ngOnInit() {
              // this method will be called every time behaviorSubject
              // emits a next value.
              this.taskService.getTasks()
                  .subscribe(tasks => this.tasks = tasks);
          }
     }
    

    View-task.component.ts

     export class ViewTaskComponent {
         constructor(private taskService: TaskService) {}
    
         updateTask(task: Task) {
             this.taskService.updateTask(task);
         }
     }
    

    I haven't tried this code myself. However, I have implemented something similar on my application before. So when you try it and have a problem, let me know.