Identifying shifts between components

Exploring Angular 4 on Github

I am currently working on a menu that is populated by a web service. The web service, taskService, is responsible for handling this feature, although it is not required at the moment.

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

Upon clicking on a task within the menu, a separate component containing a form to update the data is loaded successfully through another web service. However, the issue arises when the updated task does not reflect in the task menu.

My import statement:

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

As well as in the constructor:

private cdRef: ChangeDetectorRef

This is my attempt utilizing the detectChanges() function after updating the data with the save() function:

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

The following is the HTML code used to display the tasks within the menu:

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

Additionally, here is the form utilized to update 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>

These components are part of two distinct elements within the application.

In an effort to tackle this hurdle, I have looked into this tutorial, but remain unsure about effectively leveraging the ChangeDetectorRef.

Answer №1

Upon reviewing your code, it appears that the issue lies in the view-task.component updating tasks without notifying the navigation.component of the change. Utilizing a BehaviorSubject could address this concern effectively.

To delve deeper into this topic, you can explore more about Behavior Subjects here

The premise is to maintain a singular array of tasks within your application and showcase them on the navigation component.

Task.service.ts

export class TaskService {
     // initializing behaviorSubject with an empty array.
     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 => {
                   this.tasks.next(tasks);
              }, error => {
                   // handle errors appropriately
              });
     }

     updateTasks(task: Task) {
          this.http.post('api/updateTask')
              .subscribe(resp => {
                   // update tasks array
                   this.tasks = ...
                   // notify subscribers with updated list
                   this.tasks.next(this.tasks);
              }, error => {
                   // handle errors appropriately   
              });
     }
}

Navigation.component.ts

 export class NavigationComponent implements OnInit{
      tasks: Task[];
      constructor(private taskService: TaskService) {}

      ngOnInit() {
          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);
     }
 }

While I haven't tested this exact code snippet myself, I have employed similar approaches in my own projects. Feel free to reach out if you encounter any challenges while implementing it.

Answer №2

Angular is not automatically running `changeDetection` because you have not triggered it to do so. The instance variables in your `ViewTaskComponent` are not being updated within the `save` method.

In your current code, once `updateTask()` finishes, it returns to `save()` in `ViewTaskComponent`. However, there seems to be no reference to `this.task` within the subscription callback for `this.taskService.updateTask()`.

Since `updateTask` uses a PATCH request, it's likely that you're not receiving the complete `Task` object in return. Therefore, directly assigning `this.task = valuePassedToSubscribeCallback` won't work as expected.

Instead, consider calling `this.viewTask()` inside the subscribe callback to fetch the entire updated `Task` object.

Here is an example:

this.taskService.updateTask(task, id)
    .subscribe(
        // Add this line to fetch the updated Task object
        this.viewTask()
    );

Note: It might be beneficial to follow @Bunyamin Coskuner's advice and consider using `BehaviorSubject`s or `Subject`s in your services for better state management if you are open to making some changes.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

How can you transform a variable into an HTML element using Angular?

Currently, I am working on parsing a JSON file that contains information about various articles. The structure of the JSON file is as follows: { "articles": [ { "id": 1, "title": "<h1>How to install Atom</h1>" }, { ...

Structuring your Angular 6 application and server project

What is the recommended project structure when developing an Angular 6 application and an API server that need to share type definitions? For example: On the client side: this.httpService.get<Hero[]>(apiUrl + '/heroes') On the server si ...

Add additional characteristics to the current interface without needing to create a separate interface

Imagine I have an interface: interface Cat { name: string; age: number; color: string; } Now, I want to create an object with a new interface that extends partial Cat and adds new properties: interface MyCat extends Partial<Cat> { sex: " ...

utilizing reflect-metadata to retrieve the decorators placed on an object

There's a unique decorator in my code that seems to have no functionality: export function myDecorator(target: any, key: string) { var t = Reflect.getMetadata("design:type", target, key); } This decorator is being used with properties of a class: ...

Encountering an issue following the update from Angular 8 to 12 - receiving the error message: "The 'controls' property is not present in the 'AbstractControl' type."

Previously, I had a fully operational code in Angular 8. Recently, I made the decision to upgrade from version 8 to Angular 12. The main feature of my project is a dynamic reactive form structured in a question-answer format. This form adapts based on the ...

"Creating a Typescript function that guarantees a non-null and non-undefined return

Currently, I am working on developing a function that is designed to return a specific value. In the event that the returned value is null or undefined, the function should then default to a pre-determined value. function test<A, B>(input: A, fallba ...

Issues encountered when setting up a Context Provider in React using TypeScript

I am currently in the process of setting up a Cart context in my React TypeScript project, inspired by the implementation found here: https://github.com/AlexSegen/react-shopping-cart/blob/master/src/contexts/CartContext.js. I'm encountering some conf ...

What is the reason for the continual appearance of the *ngIf validation message?

Currently, I am working with Angular and HTML. I have implemented pattern validation for the first name field, which should not accept only numbers. <fieldset class="six"> <input id="firstName" ng-pattern="^[a-zA-Z]+$" type="text" ...

Issue with Angular/Jasmine: Undefined property 'pipe' not readable

I have been struggling to resolve a problem with Angular 9, Jasmine, and RxJS without much success. While my unit tests run successfully in Jasmine, there are certain lines of code that do not get executed. Despite scouring multiple posts for assistance, ...

Having difficulty properly streaming UI components with Vercel's AI-SDK

Recently, I've been diving into the new Vercel's AI-SDK to expand my skills. My current project involves developing a persona generator that takes specific guidelines as inputs and generates persona attributes according to a given Zod schema. B ...

Creating components on the fly as soon as their resources become available

I need to dynamically add a child component within another component only after the image inside the child component has been fully loaded. child.component.ts import { Component, OnInit } from '@angular/core'; @Component({ selector: 'a ...

What is the method to verify that an Action was sent from one Action to another in NGXS?

I've been utilizing NGXS extensively throughout an application, but there are certain tasks that I still struggle to accomplish in a satisfactory manner. The documentation and other questions on this topic haven't provided the answers I seek. One ...

TS2531: Potentially null object

I am facing an issue in my React-TypeScript project with the following code snippet. Despite having null checks, I am still getting an error "object is possibly null" while running the app. The error specifically occurs in the last part of the if conditio ...

Is it possible to obtain Literal types for object keys dynamically in typescript?

I am looking to extract the type of object keys. Below is a generic function for objects with keys as strings: type GenericInput = { [key:string]: {value:string,type:HTMLInputTypeAttribute,placeholder:string,min?:number,max?:number,required?:boolean, err ...

Navigating with Angular's routerLink based on a dynamic route parameter

My Angular application has a unique setup where the root directory is defined as a variable route parameter: /:demo_profile/(etc). One challenge I am facing is the inability to use relative paths due to the fact that my routerLink is accessible from diff ...

Enhance the appearance of a custom checkbox component in Angular

I developed a customized toggle switch for my application and integrated it into various sections. Recently, I decided to rework it as a component. However, I am encountering an issue where the toggle switch button does not update in the view (it remains t ...

Creating a new section in an Angular 2 project can be achieved by implementing an onclick function that is

Whenever I click the new button, a section with 3 fields should appear. However, even though I am not receiving any errors, I can't seem to figure out what I'm doing wrong. Click here for an example Here is the HTML: <form *ngFor="let ...

Enhancing TypeScript builtin objects in Netbeans using a custom plugin

While in the process of converting JavaScript code to TypeScript, I encountered a challenge with extending built-in objects using Object.defineProperty, such as String.prototype. Object.defineProperty(String.prototype, 'testFunc', { value: funct ...

Navigating Date Conversion within Component in Angular 2 Application

Searching for a way to update the display of certain dates in my Angular 2 application, I encountered a roadblock. Using the date pipe in conjunction with string interpolation wasn't viable due to the structure of my template code: <input class="a ...

Tips for obtaining the iframe #document with cheeriojs?

I've been struggling to scrape the anime videos page [jkanime], specifically with extracting the mp4 video formats embedded in an iframe #document. Despite trying to use cheerio for querying, I've only managed to retrieve src links from Facebook ...