Angular: How to temporarily highlight dom elements that have just changed? Angular: How to temporarily highlight dom elements that have just changed? typescript typescript

Angular: How to temporarily highlight dom elements that have just changed?


The easiest and cleaner way I can think of is to implement 2 css classes like so:

.highlight{    background-color: #FF0;}.kill-highlight{    background-color: #AD310B;    -webkit-transition: background-color 1000ms linear;    -ms-transition: background-color 1000ms linear;    transition: background-color 1000ms linear;}

and then affect both of them successively to the element.hope that helps


Here is my solution.

I wanted to highlight the datas in the Form that are changed by other users in real-time.

In my HTML form, I replaced native html elements by Angular components. For each type of native element I created a new Angular Component with Highlight support. Each component implements the ControlValueAccessor Angular interface.

In the parent form I replaced the native element:

<input [(ngModel)]="itinerary.DetailWeather" />

by my custom element:

<reactive-input [(ngModel)]="itinerary.DetailWeather"></reactive-input>

When Angular calls detectChanges() for the parent form, it does check all the datas that are used as inputs by the components of the form.

If a component is a ControlValueAccessor, and a change occurred in the application model, it does call the method ControlValueAccessor.writeValue( value ). It is the method that is called when the data changed in memory. I use it as a hook to update temporarily the style to add the highlight.

Here is the custom element. I used Angular Animations for updating the border color and fade back to the original color.

import { Component, Input, forwardRef, ChangeDetectorRef } from '@angular/core';import { ControlValueAccessor,  NG_VALUE_ACCESSOR  } from '@angular/forms';import { trigger, state, style, animate, transition, keyframes } from '@angular/animations';@Component({  selector: 'reactive-input',  template: `<input class="cellinput" [(ngModel)]="value" [@updatingTrigger]="updatingState" />`,  styles: [`.cellinput {  padding: 4px }`],  animations: [    trigger(       'updatingTrigger', [        transition('* => otherWriting', animate(1000, keyframes([          style ({ 'border-color' : 'var( --change-detect-color )', offset: 0 }),          style ({ 'border-color' : 'var( --main-color )', offset: 1 })        ])))    ])  ],  providers: [ { provide: NG_VALUE_ACCESSOR, useExisting: forwardRef(() => ReactiveInputComponent), multi: true } ]})export class ReactiveInputComponent implements ControlValueAccessor {  public updatingState : string = null;  _value = '';  // stores the action in the attribute (onModelChange) in the html template:  propagateChange:any = ( change ) => {};  constructor( private ref: ChangeDetectorRef ) { }  // change from the model  writeValue(value: any): void  {    this._value = value;     this.updatingState = 'otherWriting';    window.setTimeout( () => {      this.updatingState = null;    }, 100 );    // model value has change so changes must be detected (case ChangeDetectorStrategy is OnPush)    this.ref.detectChanges();  }  // change from the UI  set value(event: any)  {    this._value = event;    this.propagateChange(event);    this.updatingState = null;  }  get value()  {    return this._value;  }  registerOnChange(fn: any): void { this.propagateChange = fn; }  registerOnTouched(fn: () => void): void {}  setDisabledState?(isDisabled: boolean): void {};}


To highlight DOM element for a moment, use setTimeout() to add or remove CSS class

check demo

HTML

<mat-form-field [ngClass]="{'changed': isChanged}">  <mat-select [(ngModel)]="yourModel" (ngModelChange)="modelChanged($event)">     <mat-option value="1">1</mat-option>     <mat-option value="2">2</mat-option>     <mat-option value="3">3</mat-option>  </mat-select></mat-form-field>

Typescript

isChanged: boolean = falsemodelChanged(value) {   console.log('model changed')   this.isChanged = true   setTimeout(() => {       this.isChanged = false   }, 1000);}

CSS

.changed {    transition: color 0.4s ease-in, text-shadow 0.4s ease-in, background-color 0.5s linear 0s;    text-shadow: #bbb 2px 2px 2px;    background-color: #ffffcc;    color: #BF1722;}

Note: if your application changes in milliseconds then you should reduce the time for setTimeout() to 0.5s or 0.3s as per your application requirement.

Thanks to Ingo Bürk for pointing-out this issue