Best approach for implementing regular CSS modifications in Angular 2

An Angular 2 website has a websocket constantly updating data in the grid from the backend. To highlight recent updates, CSS is used to change the background color and font style of affected cells.

The highlighted indicators should only be visible for a short period.

1) At first, all indicators were reset when new data arrived from the server. However, in some cases where updates are infrequent, the indicators remained for long periods, causing confusion.

To provide a more consistent user experience, it was suggested that update indicators disappear after a fixed time interval, such as 4 seconds.

2) A second attempt involved using CSS animations, but this caused significant lag after prolonged use. It seems that running too many animations simultaneously may overload the browser's capacity to handle them effectively.

3) The latest approach involves implementing a TimerService that runs at fixed intervals to check and reset due items. While this method works, frequent violation warnings have been observed:

[Violation] 'setInterval' handler took 56ms
[Violation] 'setInterval' handler took 74ms
[Violation] 'setInterval' handler took 63ms
[Violation] 'setInterval' handler took 88ms
...

Despite the warning messages, the actual checkItems method only takes 0.03ms to execute. This discrepancy raises questions about possible optimizations or alternative frontend-friendly solutions.

  • The team has a background in C# and relatively limited experience with Angular. Could their backend-oriented mindset be affecting their frontend approaches?

  • Is there a context-switching issue that has been overlooked?

  • Are there any optimizations that could enhance the code performance?

All suggestions and insights are welcome!

Below is the implementation of the TimerService causing the violation warnings:

import { Injectable, OnInit } from "@angular/core";
import { Observable } from "rxjs/Rx";
import { Subject } from "rxjs/Subject";

@Injectable()
export class TimerService {
    private timerItems: TimerItem[] = [];
    private dueTimeReachedSubject: Subject<string> = new Subject<string>();
    public dueTimeReached: Observable<string> = this.dueTimeReachedSubject.asObservable();

    constructor() {
        setInterval(() => this.checkItems(), 1000);
    }

    private checkItems() {
        let now = Date.now();
        let removeKeys: string[] = [];
        this.timerItems.filter(t => t.dueTime <= now).forEach(t => {
            this.dueTimeReachedSubject.next(t.key);
            removeKeys.push(t.key);
        });
        this.timerItems = this.timerItems.filter(t => removeKeys.indexOf(t.key) < 0);
    }

    public add(key: string, delayInSeconds: number) {
        let dueTime = Date.now() + delayInSeconds * 1000;
        let timerItem = this.timerItems.find(t => t.key === key);
        if (timerItem) {
            timerItem.dueTime = dueTime;
        }
        else {
            this.timerItems.push(new TimerItem(key, dueTime));
        }
    }   

    public remove(key: string) {
        this.timerItems = this.timerItems.filter(t => t.key !== key);
    }
}


class TimerItem {
    constructor(public key: string, public dueTime: number) { }
}

EDIT

Attempts were made to improve the service by utilizing Observable.interval and setTimeout; however, the same warning messages persisted. Even emptying the checkItems method did not resolve the warnings, indicating that the issue lies within the Angular framework itself.

While warnings for slow functions may be expected, the concern arises when a simple setInterval function triggers these alerts. Understanding why this occurs becomes crucial for optimizing the code execution speed.

Answer №1

There are a multitude of actions that can be taken in a setting such as this.

Firstly, consider adjusting the ChangeDetectionStrategy to ChangeDetectionStrategy.onPush. Activate detection only when necessary, such as at the conclusion of checkItems, add, and remove operations. By doing so, Angular will minimize script evaluation to instances where it is expressly required.

Secondly, evaluate whether your template contains function calls within an *ngIf or *ngFor. When functions are utilized in these directives, Angular cannot cache their return values, resulting in repetitive processing during each check operation.

The third point to keep in mind is optimizing checkItems, which currently runs in O(n^2) time complexity and performs unnecessary iterations. Consider streamlining this process for improved efficiency.

checkItems() {
  this.timerItems = this.timerItems.filter(t => {
      if(t.dueTime <= now){
          this.dueTimeReachedSubject.next(t.key);
          return false;
      }
      return true;
  });        
}

While this may not have a significant impact on small arrays, the benefits become more pronounced as array size increases.

These three suggestions helped me address similar performance issues I encountered.

Answer №2

Instead of using setInterval, I recommend utilizing setTimeout only when it is needed.

import { Injectable, OnInit } from "@angular/core";
import { Observable } from "rxjs/Rx";
import { Subject } from "rxjs/Subject";

let timer = null

@Injectable()
export class TimerService {
    private timerItems: TimerItem[] = [];
    private dueTimeReachedSubject: Subject<string> = new Subject<string>();
    public dueTimeReached: Observable<string> = this.dueTimeReachedSubject.asObservable();

    constructor() {
        this.checkItems();
    }

    private checkItems() {
        // clear the timeout
        clearTimeout(timer)
        let now = Date.now();
        let removeKeys: string[] = [];
        this.timerItems.filter(t => t.dueTime <= now).forEach(t => {
            this.dueTimeReachedSubject.next(t.key);
            removeKeys.push(t.key);
        });
        this.timerItems = this.timerItems.filter(t => removeKeys.indexOf(t.key) < 0);
        // only use the timer if there are timerItems
        if(this.timerItems.length) {
            timer = setTimeout(() => this.checkItems(), 1000)
        }
    }

    public add(key: string, delayInSeconds: number) {
        let dueTime = Date.now() + delayInSeconds * 1000;
        let timerItem = this.timerItems.find(t => t.key === key);
        if(timerItem) {
            timerItem.dueTime = dueTime;
        }
        else {
            this.timerItems.push(new TimerItem(key, dueTime));
        }
        // check for items and engage the timer if necessary
        this.checkItems()
    }   

    public remove(key: string) {
        this.timerItems = this.timerItems.filter(t => t.key !== key);
    }
}


class TimerItem {
    constructor(public key: string, public dueTime: number) { }
}

Answer №3

It seems like you are looking for a way to have CSS changes revert back after a specific time period.

  1. To achieve this, create separate CSS classes for the normal and updated states of cells and rows:

.row-normal{
//css-styling goes here
}
.row-updated{
//css- here
}

---Approach 1--- Set an update listener Define an onChange attribute for your views in HTML or utilize document.getElementByTagName in JavaScript code.

function onUpdate(){
  let element = this;
  element.className = "row-updated";
  setTimeOut(function(){element.className = "row-normal"}, interval_in_millis)
}

I hope this solution helps with your query.

Answer №4

Have you double-checked that you recompiled your project after removing the code from checkItems?

My understanding is that the issue may be related to the checkItems function taking too long.

Just to be thorough, I created a StackBlitz demo

I tested your code in the StackBlitz environment and was unable to replicate the problem.

If you're still experiencing difficulties, perhaps you could duplicate the StackBlitz and attempt to reproduce the error there?

Answer №5

To address this issue, consider utilizing React's animation functionalities.

As an illustration, when new elements are included in a list, they trigger the :enter transition event (equivalent to void => * transition). Here is a snippet from the accompanying documentation:

JSX:

<CSSTransition classNames="fade"&timeout={300}>
  <div className="new-element">
    New Element Added
  </div>
</CSSTransition>

JavaScript:

<CSSTransition classNames="fade" timeout={300}>
  {state === "added" && (
    <div className="new-element">
      New Element Added
    </div>
  )}  
</CSSTransition>

When the element with the fade class undergoes the ":enter" transition, it will start with opacity: 0 and gradually transition to opacity: 1 over a duration of 300 milliseconds.

The first parameter of the CSSTransition component (e.g., {300}) can also specify additional attributes like timing and easing functions. If you want to apply a particular style to new items for 4 seconds, you could implement a similar transition rule:

<CSSTransition classNames="fade" timeout={{ enter: 1000, exit: 4000 }}>
  {state === "added" && (
    <div className="custom-style">
      Custom Style Applied
    </div>
  )}
</CSSTransition>

This approach will instantly give new items a custom style and after 4 seconds, transition them to another specified style, lasting 1 second in total.

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

Encountered an issue accessing property 'Component' which is undefined during the webpack build of a React component plugin

I have developed a wrapper for my leaflet plugin called leaflet-arrowheads using react-leaflet. This component is designed to be installed as an npm package, imported, and used easily. The structure of the component is quite simple: import React from &apo ...

An error has occurred: sendEmail function is not defined

There seems to be a simple issue here that needs my attention before diving into PHP tasks. I plan on using PHPMailer this time around. I've been attempting to learn how to submit a form on localhost for the past week, and now I'm going to try i ...

What is the proper way to set up Node modules in a subdirectory?

Is there a recommended approach for generating the node_modules folder in a subfolder? I am currently using Bower to install client-side files under a "client" folder and would like to do the same with NPM for server-side dependencies. For instance: MyApp ...

Creating a simulated dropdown menu using only CSS

I was able to create a select menu using only CSS, following some code I found. However, I am now facing an issue with overlaying divs. Whenever I hover or click on the "select menu", all the divs below it move down. I've attempted to adjust the z-i ...

Wcf Service does not define Angular JS methods

I am utilizing a WCF Service within an AngularJS application. The WCF Service is functional, and I am attempting to display a list of user records from a SQL database. However, upon running the application, I encountered the following errors: angular.js: ...

Using the MoveToElement and click functions in Protractor with Node.js for automated browser

Trying to click on a checkbox in our application. I have successfully implemented it in Selenium Java using the code below, but struggling to do the same in Protractor Node.js. Any assistance would be appreciated. Selenium- Java : Actions actions ...

Having trouble with an error message popping up when importing the "ngx-bootstrap/datepicker" module in Angular 6

Attempting to incorporate the ngx Bootstrap datepicker into my Angular Application, I followed these steps: To npm install ngx-bootstrap npm install ngx-bootstrap --save Installed bootstrap 3 npm install bootstrap@3 --save In angular-cli.json file, s ...

SlipHover js functions perfectly on all devices except for iPhones

Recently, I created a simple details page that showcases a product image. When you hover over the image, an overlay slides in with additional information about the product. I was able to achieve this effect using sliphover.js, which can be found at Initia ...

Utilizing JQuery Ajax to Retrieve Conversion Explanations

In my project, I have a set of AJAX wrapper functions that I use to make AJAX requests. I am now considering switching to using the Fetch API instead. As a newcomer to this transition, I have some questions and concerns that I think will be beneficial for ...

extract information from an external JSON document

I have a JSON file filled with data, along with a JSX file containing a button and a div. I'm looking to extract the data from the JSON file and display it in the div when the button is clicked. However, I'm at a loss on how to achieve this. The ...

Display sourcemaps on Chrome's network panel

Recently, I began utilizing source maps for my SASS code in order to debug more efficiently in Chrome. My understanding was that Chrome should request both the stylesheet resource and the .map resource, however, only the stylesheet is visible in the netwo ...

"Spinning Effect in CSS with a Pulsating Twist

I am attempting to create a unique CSS animation that involves rotating an image and giving it a pulsing effect similar to the animation seen on Shazam's button. Here is the code that I have so far. While the image is successfully rotating, I am runn ...

Troubleshooting a problem with Socket IO

I am facing an issue where my code is not logging any messages in the console when I run my server. I need it to log a message upon running the server. On the server side const path = require('path'); const http = require("http"); const express ...

Passport.js unable to establish session during cross-domain requests

Currently, I am implementing login using the passport.js local strategy and facing issues with setting sessions. My setup involves two servers - localhost:3000 for node and another server at localhost:4200. I need to establish session on requests origina ...

Page loading: Centered around a designated spot

Currently, I am working on a website where the layout is quite unconventional and the positions are fixed. The page size is set at 1450 x 900 pixels. What I am aiming to achieve is for the page to load with a different starting point than the typical top:0 ...

Incorporate an object property value into an established Angular/Node app by using the syntax " :12 " instead of just " 12 "

My current project is an Angular/Node MEAN stack application, but my primary concern revolves around JavaScript. When I receive a response object, it includes an SQL identity id console.log(response.recordset[0]); The output is "":12 I want to assign t ...

Tips for creating a clickable image inside a span button

I am trying to create a clickable button that includes a span with a .png image inside. Currently, the button only responds when I click around the image, not directly on it. I have searched for solutions but haven't found one that addresses my specif ...

Using Material UI v1 to customize the widths of table columns

I am looking to configure column widths on a Material UI table using CSS, rather than within React with "classes." However, I am struggling to understand how the column widths are actually controlled. Despite trying to set widths on the TH columns, it does ...

How can a JavaScript code be used to navigate to a different HTML file within the same directory that is stored within a folder?

Here is the sample HTML code: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewpor ...

Can you tell if there are any distinctions between the two code snippets?

Initial Code console.log('Begin'); // output 1 await axios({ method: 'post', url: '<HTTP_URL>' data: <SOME_DATA>, }).then ((response) => { // Performing some action... This may take a few seconds. con ...