Angular Component Blinking when Observable Data is Updated

I have been developing an Angular component called GestionAchatTpvGenerationProgressBarComponent, which is responsible for showcasing a progress bar based on data from an Observable. This self-contained component operates with the OnPush change detection strategy and aims to illustrate the progression of specific purchases made through a TPV (Point of Sale Terminal) by updating via a stream of data (achatTitreViaTpv).

However, there seems to be a noticeable "flickering" effect or visible refresh each time the achatTitreViaTpv data is updated, resulting in a subpar user experience. I am keen on understanding the rationale behind this behavior and finding ways to mitigate it.

Below is a simplified version of the component's code:

@Component({
  selector: 'app-gestion-achat-tpv-generation-progress-bar',
  templateUrl: './gestion-achat-tpv-generation-progress-bar.component.html',
  styleUrls: ['./gestion-achat-tpv-generation-progress-bar.component.scss'],
  changeDetection: ChangeDetectionStrategy.OnPush,
  imports: [
    TranslateModule,
    NgIf,
    AsyncPipe,
    DecimalPipe
  ],
  standalone: true
})
export class GestionAchatTpvGenerationProgressBarComponent {
  @Select(GestionAchatTpvDetailState.recupereAchat) achatTitreViaTpv!: Observable<AchatTitreViaTpv>;
}

And the corresponding template:

<div class="progress-bar-tpv-generation-container">
    <ng-container *ngIf="achatTitreViaTpv | async as achat">
        <div class="progress-bar-tpv-generation-container__titles-container">
            <!-- Display of progress and estimated remaining time -->
        </div>
        <div class="progress-bar-tpv-generation-container__progress-bar">
            <div class="progress-bar-tpv-generation-container__progress-bar--fill" [style.width]="(condition) + '%'"></div>
        </div>
    </ng-container>
</div>

My attempted solutions include:

  • Optimizing data updates to prevent unnecessary re-emissions.
  • Utilizing the OnPush change detection strategy to reduce change checks.

Despite these efforts, the flickering issue persists whenever data is updated. Can anyone shed light on the potential causes of this behavior and suggest how it can be resolved?

Answer №1

There are several potential causes for the issue you're facing:

  • Have you checked if any ancestor component in the parent tree is causing unnecessary re-renders?
  • How frequently does the re-render occur? It may be helpful to subscribe to the stream and observe the behavior.
export class GestionAchatTpvGenerationProgressBarComponent implements AfterViewInit {
  @Select(GestionAchatTpvDetailState.recupereAchat) achatTitreViaTpv!: Observable<AchatTitreViaTpv>;

  ngAfterViewInit() {
    this.achatTitreViaTpv.subscribe({next: (val) => console.log("update:" + val); // something like that
  }
}

Frequent updates can lead to container flickering, especially if there are gaps in the data (e.g., progress jumping from 4% to 5% to null to 6%).

  • Have you tried removing the async part from the ngIf and checking for null just once? Change

     *ngIf="achatTitreViaTpv | async as achat"
    to
     *ngIf="achatTitreViaTpv != null"

  • If the changes are occurring too frequently (multiple times per second), consider implementing throttle mechanisms. Since you're already using RxJS in Angular, you could explore using the throttle operator.

Answer №2

The issue lies in the frequent triggering of Angular's Change Detection system. A potential solution is to implement Angular Signals for better control.

Here is the updated code snippet for the modified component:

import { OnInit, WritableSignal, signal } from '@angular/core';

//(...)

export class UpdatedComponent implements OnInit {
  
    dataToUpdate?: Observable<DataModel>;
  
    dataUpdateSignal: WritableSignal<DataModel | undefined> = signal(undefined);
  
    ngOnInit(): void {
      if(this.dataToUpdate) {
        this.dataToUpdate.subscribe((data: DataModel) => {
          //TODO: Check for changes in the line below:
          if(data.id != this.dataUpdateSignal()?.id ?? 0) {
            this.dataUpdateSignal.set(data);
          }
        });
    }
  } 
}

Revised line within the ng-container:

<ng-container *ngIf="this.dataUpdateSignal()">

I trust this brings clarity to the situation.

Note: Please provide additional code samples if further assistance is required.

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

Angular: Troubleshooting - potential bug in test case with jasmine causing TypeError: Undefined property 'cmd' OrAngular: Debugging

I'm working on writing a unit test case for integrating lotame analytics. Can anyone offer some assistance on how to write a test case for this integration? I've been stuck on this for quite some time now and keep receiving TypeError: Cannot read ...

Are there better options than Angular timer, or is it still the top choice?

Currently, I am utilizing Angular 8 for a project where I have implemented a component that includes a checkbox to toggle the visibility of the footer. Since the footer is a distinct component from the settings component, I find myself needing to use a se ...

Incorporating a CSS Module into a conditional statement

Consider the following HTML structure <div className={ `${style.cell} ${cell === Player.Black ? "black" : cell === Player.White ? "white" : ""}`} key={colIndex}/> Along with the associated CSS styles .cell { ...

Assigning value to a member variable in a TypeScript Angular class

Currently, I am in the process of learning Angular. To enhance my skills, I am developing a simple web application using Angular and Spring Boot. One challenge I encountered is assigning a variable to the member variable of a Class. import { Injectable } f ...

The angular matAutocomplete box is positioned beneath the bootstrap navbar element

Trying to integrate angular material matAutocomplete mat-options into a bootstrap Navbar, here's what the code looks like: <li class="nav-item"> <form class="example-form"> <mat-form-field class="example-full-width"> < ...

The file is missing the required fields in the Firestore document

I've been facing a challenge while attempting to update specific fields within a firebase document. Even though the cloud function triggers and performs an upload on the document, the values of the fields I am trying to update never seem to get upload ...

Utilizing a function in an infinite loop within *ngFor along with an asynchronous pipe for an HTTP call

Using a function in an *ngFor statement: @Component({ selector: 'foo-view', template: '<div *ngFor="let foo of loadAll() | async"></div>' }) export class FooComponent { loadAll(): Observable<Foo[]> { return ...

Is there a way to retrieve a compilation of custom directives that have been implemented on the Vue 3 component?

Is there a way to retrieve the list of custom directives applied to a component? When using the getCurrentInstance method, the directives property is null for the current component. I was expecting to see 'highlight' listed. How can I access the ...

Unlocking the power of variables in Next.js inline sass styles

Is there a way to utilize SASS variables in inline styles? export default function (): JSX.Element { return ( <MainLayout title={title} robots={false}> <nav> <a href="href">Title</a> ...

node js rest API returns a response of an empty request body when receiving form data

I have set up an HTML form to save data into MSSQL Check out the form below: <form [formGroup]="insProtocolloForm" (ngSubmit)="sumit()" enctype="multipart/form-data"> <div class="modal-dialog modal-dialog-ce ...

Warning: Unresolved promise: NullInjectorError encountered: StaticInjectorError(AppModule) when trying to use FormBuilder

I encountered an error in my Angular app when adding routes in gifts-routing.module.ts. The error disappears when I remove the routes, but I still need to implement routing. How can I resolve this issue? ERROR Error: Uncaught (in promise): NullInjectorErr ...

There seems to be an issue with the Typescript code as it is showing an error

I have declared the type and provided the reminderInfo object: type ReminderProps = { reminderInfo?: { buttonText?: string | undefined; url?: string | undefined; }; }; const customComponent: FunctionComponent<ReminderProps> = ({ remind ...

Utilize the error message as a label following the submission of the form

I need to implement a password reset form for user authentication purposes. Below is the HTML code: <form class="grid-wrapper" #f="ngForm" *ngIf="stepOne"> <div class="form-group first-row"> <label for="name">Username</label> ...

I am looking to use Angular Material to perform a calculation on two mat-cell input values and display the result in a separate mat-cell within dynamically added columns

A mat-table has been created with dynamically added columns. The goal is to perform an operation in two columns (Unit Price * Qty/Rolls) and display the results in the Amount column. In the footer, the total Qty/Rolls and amount should be shown. Here' ...

Angular 10 edit mode issue: Unable to set selected value in dropdown

Why is the value from the database not selected in the edit mode of the form? Even though I am getting the correct value in 'service.formData.SalesRepId', it is not being selected. Is there something I am overlooking? https://i.sstatic.net/DLtfr ...

A method for cycling through parent and child objects in JavaScript (Vue.js) and storing them in an array - how to

I have a JSON object structured like this. const jsonData = { "id": "6", "name": "parent", "path": "/", "category": "folder", "fid": "6", "children": [ { ...

"Exploring the Powerful Combination of NGRX Effects with Angular

Seeking assistance to understand the issue at hand. I have implemented an ngrx effect that interacts with an auth service. The service call is functioning correctly, and error handling is in place as well. The challenge I am facing is that upon a success ...

Server request successful, but CORS error occurs in browser

When I make an HTTP POST request to the Microsoft login in order to obtain an access token for use with the mail API, the request is successful but my code still goes to the error clause. requestAccessToken(code: string) { console.log("Requesting access t ...

Ways to require semicolons in a Typescript interface

When declaring a TypeScript interface, both , (comma) and ; (semicolon) are considered valid syntax. For example, the following declarations are all valid: export interface IUser { name: string; email: string; id: number; } export interface IUser { ...

How to retrieve various data points from a service and pass them to a component in

Utilizing an httpmodule to fetch data from the backend, I am faced with a challenge. While loading data in the service and returning it to the component, I also need to send a status code along with it. Unfortunately, the Data model is already set and cann ...