View not being updated by Angular's ngOnChanges

Summary: Trouble with detecting changes in an input property in Angular app

Currently, in my Angular (2+) application, I am attempting to create a progress bar to track the progress of an asynchronous task handled by a service using an Observable. The Observable sends numbers as data to indicate the percentage of completion of the task. There are three key components involved: The Service, ResultsComponent, and ProgressBarComponent (which is a child component of ResultsComponent). The flow of data goes like this:

  1. The Observable sends a number to ResultsComponent
  2. The ResultsComponent sets percentLoaded equal to this number
  3. ProgressBarComponent uses percentLoaded as an Input and should update the view accordingly

However, there seems to be an issue as the view is not updating as expected.

In ResultsComponent, the code snippet looks like this:

this.service.doTheTask()
    .subscribe(
      data => {
        this.percentLoaded = data;
        this.ref.detectChanges();
      },
      e => console.log('error:', e),
      () =>  {
        this.isLoading = false;
        this.percentLoaded = 0;
      }
    );

By adding ref.detectChanges(), the OnChanges hook successfully triggers in ProgressBarComponent. Below you can find the code snippets for the Component and Template:

Component

export class ProgressBarComponent implements OnChanges {
  @Input() percentLoaded = 0;

  constructor() { }

  ngOnChanges(changes) {
    console.log('changes: ', changes);
  }
}

Template

<div class="meter">
  <div class="percent" [style.width.%]="percentLoaded"></div>
</div>
<p>{{percentLoaded}}% Loaded</p>

As seen above, I am simply logging the changes to investigate. It has been confirmed that ngOnChanges is triggering and the values are correct. According to the information I've gone through, "Once changes are detected, the view will automatically update," so I'm unsure about what else could be done.

Any suggestions or advice?

Answer №1

Once your asynchronous task is completed, it's important not to reset the data you retrieved from the subscription by using the line this.percentLoaded = 0;. This line should be removed:

() =>  {
   this.isLoading = false;
   // Remove this line this.percentLoaded = 0;
}

In addition, keep in mind that the change detection may not be triggered because it only works when the reference of an object is changed. Since numbers are simple variables and not references, change detection won't be triggered in your case. I recommend subscribing to the service in both components and triggering the change detection only from the child component.

export class ProgressBarComponent {
  percentLoaded: number = 0;

  constructor(private ref: ChangeDetectorRef, private service: TheService) { }

  this.service.doTheTask()
   .subscribe(
     data => {
     this.percentLoaded = data;
     this.ref.detectChanges();
   },
}

Answer №2

After encountering a familiar problem, I dedicated about an hour to troubleshooting until it occurred to me that I had implemented the change detection strategy onPush in the parent component.

Once I removed this, the child component began functioning as expected. Despite the ngOnChanges method being triggered, my view failed to update within the subscribe closure.

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

Revolutionize Your Web Development with ASP.NET Core and Angular 2 Integration using Webpack

I have started a new ASP.NET Core 1.0.1 project and I am working on integrating Angular 2 from scratch with Webpack Module Bundler. My goal is to use Hot Module Replacement (HMR) through ASP.NET Core SpaServices in order to avoid browser reloads, but I am ...

Leverage the TypeScript-generated controller within an Angular directive

I currently have an Angular controller that was generated using TypeScript: class FileManagerController { ... constructor($scope) { $scope.vm = this; ... } ...functions... } Can you guide me on how to integrate this controller i ...

Mastering the intricacies of Angular bindings through intuition

I am attempting to grasp the concept of distinguishing between square brackets binding <elem [...]="..."><elem> and parentheses binding <elem (...)="..."<elem>. Is there a rule of thumb that can help differentiate between the two? Pe ...

Press the text in a React Native TypeScript component to trigger a render

I am a newcomer to React Native and TypeScript, and I am struggling to figure out how to display something on the page of my app after a button is pressed. Below is the function I'm using: const getRandomNumber = () ={ const number = Math.fl ...

using outlines for FontAwesome icons in React Native

I am struggling to use the fontAwesome + icon in the middle of a circle as one item. I have tried placing it inside a circle icon, but it doesn't seem to work properly. import IconFA from 'react-native-vector-icons/FontAwesome'; < ...

Breaking data in Ionic 3 and displaying it using the Angular trunk option

When fetching data from an API, I encountered some wordings that are contained within a single string. To display them separately, here's how they appear in the console: https://i.sstatic.net/daZHV.png However, I would like to present them in my app ...

What exactly do we mean by the term 'object literal' within the realm of TypeScript?

When diving into TypeScript, the term 'object literal' comes up frequently (like in this answer) - but what exactly does 'object literal' mean and how is it different from just an 'object'? For more insight, you can check out ...

Is there a way to display a KaTex equation in Angular? I attempted to utilize ng-katex, but unfortunately, it did not produce the desired outcome

Having recently delved into Katex/Latex, I have attempted various methods but still struggle to produce the desired output. Despite using katex.org's autorender function and designated delimiters, line breaks and symbols are not rendering correctly. ...

Utilize various CSS classes on Vertical Tab React-ts for enhanced styling

Looking for help with applying an additional class (let's call it my-custom-class) to Vertical Tabs when a tab is clicked. I'm new to CSS and would appreciate any guidance. const handleChange = (event: React.SyntheticEvent, newValue: number) ...

Looking to retrieve the selected item from the list using console.log

Brief explanation: I am trying to retrieve the clicked item from a list using console.log(i.match). Please refer to my **home.html** code snippet below for how the list is dynamically generated. home.html <ion-card> <ion-card-content *ngFor="l ...

The parameter type '(req: Request, res: Response, next: NextFunction) => void' does not match the type of 'Application<Record<string, any>>'

I'm currently working on an Express project that utilizes TypeScript. I have set up controllers, routers, and implemented a method that encapsulates my controller logic within an error handler. While working in my router.ts file, I encountered an err ...

Redux-toolkit payload does not recognize the specified type

While working on my project, I encountered an issue when using redux-toolkit. I have created the following reducer: setWaypointToEdit: (state, action: PayloadAction<WaypointToEditPayload>) => { let gridPolygonsData: GridPolygonsData; const { ...

How can I assign Angular 2's HTTP object to a variable?

Here is the code I am currently using: private ARRAYDATA: any[]; constructor(private http: Http) { this.getCards('data.json'); } getCards(url) { this.http.get(url) .map(response => response.json()) .subscr ...

Angular uploading image via WCF service call

I have been facing an issue while trying to upload an image from my Angular frontend through wcf. The upload process is successful and I receive a success message, however, the saved image is not viewable in any image viewer or program. The code snippet u ...

When using TypeScript with React, you may encounter an error stating that the type 'Element' cannot be assigned to the type 'FunctionComponent<{}>'

I'm currently in the process of transitioning a react project to TypeScript and I've encountered an issue. Here's the scenario: I have multiple Chapter components, each associated with unique data and a unique Map component. Each Chapter com ...

Guide on utilizing jasmine's spy functionalityAlways remember to use the

I am a beginner when it comes to Angular and Jasmine, and I am encountering difficulties while attempting to mock: public uploadFile(confirm) { this.uploadModalRef.close(); if (this.filePath.length) { let ngbModalOptions: NgbModalOptions = { ...

Angular 4 - Unexpected path match failure triggered by route query parameters

After scouring through multiple discussions and questions regarding the different routing options in Angular 4, I have been unable to resolve an issue related to passing queryParams to an Angular 4 route. Whether passing them into the URL like this http: ...

Ensuring Type Safety in Typescript: Service Fails to Return Expected Class Object

Can you help me with this issue? Here is the code for the user service: import { Injectable } from '@angular/core'; import { HttpClient } from '@angular/common/http'; import { User } from './user'; @Injectable() export clas ...

Setting active state for nested ngFor in an unordered list using Angular 6

I utilized *ngFor inside an unordered list structure as follows: <div *ngFor="let q of questions; let i = index;"> <label>{{ q.questionDesc }}</label> <ul class="list-group"> <li class="list-group-item list-group-item-action" ...

Creating a personalized menu using Nextron (electron) - Step by step guide

I'm currently in the process of developing an app with Nextron (Electron with Nextjs and Typescript). Although I have the foundation of my Next app set up, I've been encountering issues when attempting to create a custom electron menu bar. Every ...