The interface in Angular fails to refresh after the information is modified within its scope

It seems like I might be overlooking something. Currently, my subscription is set up in a way that local changes made with the typeWriter function inside the component do not update the UI accordingly. The UI only updates when changeDetectorRef.detectChanges() is used, which doesn't seem to be the most efficient method for handling local changes.

    import { Component, Input, OnDestroy, OnInit } from '@angular/core';
import { IconDefinition, faCopy } from '@fortawesome/free-solid-svg-icons';
import { HotToastService } from '@ngneat/hot-toast';
import { Store } from '@ngrx/store';
import { Subscription } from 'rxjs';
import { InitialState } from '../../../../../../store/store';
import { storeActions } from '../../../../../../store/store.actions';
import { selectPrinting } from '../../../../../../store/store.selectors';
import { MessageI } from './message.types';
@Component({
  selector: 'app-message',
  templateUrl: './message.component.html',
  styleUrl: './message.component.scss',
})
export class MessageComponent implements OnInit, OnDestroy {
  /**
   * Chat object which contains properties {from & message}
   */
  @Input() chat: MessageI;
  private subscriptions: Subscription[] = [];
  public printing$: boolean;

  public copyIcon: IconDefinition = faCopy;

  public copyIconStyle = {
    dimensions: {
      height: 20,
      width: 20,
    },
    style: { color: 'white', cursor: 'pointer', width: 'max-content' },
  };

  public setIntervalID: number;
  public printedMessage: string = '';

  get imageUrl(): string {
    return this.chat.from === 'You'
      ? 'assets/images/me.jpg'
      : 'assets/images/cat.png';
  }

  constructor(
    private toast: HotToastService,
    private store: Store<{ store: InitialState }>
  ) {}

  ngOnInit(): void {
    this.subscriptions.push(
      this.store.select(selectPrinting).subscribe((vl) => {
        this.printing$ = vl;
      })
    );

    if (this.chat.from === 'You') {
      this.printedMessage = this.chat.message;
      return;
    }

    this.typewriterEffect(50);

    this.store.dispatch(storeActions.printingHandler());
  }

  ngOnDestroy(): void {
    this.subscriptions.forEach((s) => s.unsubscribe());
  }

  copyMessage() {
    this.toast.success('Copied to clipboard!', {
      duration: 5000,
      style: {
        border: '1px solid #713200',
        padding: '16px',
        color: '#713200',
      },
      iconTheme: {
        primary: '#713200',
        secondary: '#FFFAEE',
      },
    });
    navigator.clipboard.writeText(this.chat.message);
  }

  typewriterEffect(speed: number) {
    // Has to be used from window otherwise theres typescript errors that it needs to be Nodejs.Timeout which prompts another error
    // conflicts with Nodejs enviroments
    this.setIntervalID = window.setInterval(() => {
      if (
        this.printedMessage.length !== this.chat.message.length &&
        this.printing$
      ) {
        this.printedMessage = this.chat.message.slice(
          0,
          this.printedMessage.length + 1
        );
      } else {
        this.store.dispatch(storeActions.printingHandler());
        clearInterval(this.setIntervalID);
      }
    }, speed);
  }
}

Answer №1

The reason behind this phenomenon is that the change detection cycle does not get triggered when your observable emits values.
One workaround for this issue is to utilize the async pipe to ensure that the change detection mechanism is activated each time your observable emits.

In the scenario you provided, you could implement the following approach:

    this.printing$ = this.store.select(selectPrinting)

Instead of:

    this.subscriptions.push(
      this.store.select(selectPrinting).subscribe((value) => {
        this.printing$ = value;
      })
    );

In the HTML template, you can include:

<ng-container *ngIf="printing$ | async as printing">
// place your HTML code that uses the printing variable here,
// reference it in the template as 'printing'
</ng-container>

It's worth mentioning that it is a common practice to append only Observables with a dollar sign '$'.
Furthermore, now that printing$ is an Observable, adjustments will be required throughout the component to accommodate this change.

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

Navigating with Angular 4's router and popping up modals

I have an Angular 4 SPA application that utilizes the Angular router. I am looking to create a hyperlink that will open a component in a new dialog using Bootstrap 4. I am able to open modal dialogs from a function already. My question is, how can I achi ...

What could be causing my redirection to not load the correct component as expected?

I'm encountering an issue with my Angular application where a redirect in the routing module is not hitting the expected routes and instead falls through to the wildcard route. Here's a simplified example of the problem: const routes: Routes = [ ...

Utilize Tailwind CSS in React to dynamically highlight the active navigation item on click

Check out my navigation bar code: <nav className="bg-white shadow dark:bg-gray-800"> <div className="container flex items-center justify-center p-6 mx-auto text-gray-600 capitalize dark:text-gray-300"> <Link ...

Displaying Modal from a separate component

CardComponent: export class Card extends Component<Prop, State> { state = { isCancelModalOpen: false, }; marketService = new MarketService(); deleteMarket = () => { this.marketService .deleteMar( ...

How to close an Angular2 modal by clicking outside the modal area

I have created a sample code that allows clicking outside to disable selection. Currently, the deselect functionality only works after clicking on the element to activate the listener. I am looking to modify this code to implement a feature where clicking ...

How Angular can fetch data from a JSON file stored in an S3

I am attempting to retrieve data from a JSON file stored in an S3 bucket with public access. My goal is to parse this data and display it in an HTML table. http.get<Post>('https://jsonfile/file.json').subscribe (res => { cons ...

Experiencing unexpected output from Angular model class method

I have developed a user-friendly Invoicing & Inventory management application that showcases a list of invoices for each customer. However, there seems to be an issue with the calculation of the Grand Total function, which I am struggling to rectify due to ...

Simple methods for ensuring a minimum time interval between observable emittance

My RxJS observable is set to emit values at random intervals ranging from 0 to 1000ms. Is there a way to confirm that there is always a minimum gap of 200ms between each emission without skipping or dropping any values, while ensuring they are emitted in ...

What is the best way to extract the primary base64 value from reader.result?

After successfully retrieving the base64 value of my file, I noticed that along with the value, I am also getting the type of file and the type of string. However, I only require the actual value in order to send it to the backend. Code for converting fil ...

Determine the return type of a function based on the parameter type that is inferred

I am seeking to define a simple function that checks a condition and returns either a value or a default. In most cases, the default is constant, so it would be beneficial to return a union of expected and default value types to properly narrow it down at ...

Ways to resolve the TypeScript reference issue

I am encountering a TypeScript error in the code snippet below, even though I specified it as Record<"abc", string>? interface IFoo { key ?: | string | Record<"abc", string> | boolean | string[] } const tes ...

Refreshing data from firebase on each route change

I created an Angular service that retrieves items from Firebase using snapshotChanges and returns them. In my component, I subscribe to the data and store it in an array. I then display the data in cards using ngFor. However, whenever I navigate between p ...

Discover information about the client using the node.js net library

I have implemented a nodejs cluster with socket.io, where the master thread uses the net library to listen on a port and pass connections to workers based on the client's IP address. Everything is functioning properly, but I am interested in testing b ...

Tips for utilizing NgFor within Angular 2 to highlight an active item on a different HTML element

Utilizing NgFor for iterating over a collection: this.articles = [ { id: 1, title: “Tile 1“, summary: “First Article“ }, { id: 2, title: “title 2“, summary: “Summary 2“ }, ...

Instructions for utilizing a specific router-outlet within a main router-outlet:

I have a main router-outlet within my side-nav component, and I have created two additional router-outlets inside it. This is the structure: router-outlet (main) { router-outlet name='info' { } router-outlet name='servic ...

Navigating the complexities of extracting and storing a data type from a collection of objects

Dealing with a messy API that returns inconsistent values is quite challenging. Instead of manually creating types for each entry, I am looking for a way to infer the types programmatically. One approach could be by analyzing an array like this: const arr ...

Preventing Undefined Values in RxJS Observables: A Guide

I am facing an issue with passing the result of a GET request from Observable to Observer. The problem lies in the fact that the value becomes undefined because it communicates with the observer before the GET execution finishes. observer:Observer<a ...

Prevent Bootstrap 4 dropdown from closing on click in Angular 2

Could someone help me prevent the dropdown from closing automatically when clicking inside it? Here is the code snippet: <li class="nav-item dropdown"> <div ngbDropdown class="d-inline-block"> <a class=" ...

Having trouble compiling after updating Angular CLI

After switching out my computer and updating to the latest version of Angular CLI, I encountered an error in my project that I couldn't find any information on online. ERROR in ./node_modules/@angular/fire/messaging/messaging.js 23:40 Module parse fa ...

Ways of utilizing a dynamic key for invoking a resource from prisma

Currently, I am attempting to implement a more general method to retrieve data from Prisma. The function in question appears as follows: import { Prisma, PrismaClient } from '@prisma/client'; import { NextApiRequest, NextApiResponse } from ' ...