How many time ngStyle is applied

Viewed 1255

I am applying color to div element and i am changing color in cycle as follow

 toogleColor()

{

if(this.color=='blue')
{
  this.color="red"
  this.fontcolor='white'
  return
}else if(this.color=='red'){
  this.color='white'
  this.fontcolor='black'
  return
}else if(this.color=='white'){
  this.color='blue'
  this.fontcolor='white'
  return
}

}

and I have setStyle() function as follow:

  setStyle(){
this.toogleColor()
return {

  'background-color':this.color,
  'height':'382px'
}

}

In my component html I binded style as follow:

<div  [ngStyle]="setStyle()"  *ngFor="let element of array1">

But i am not Getting expected color cycle because setStyle() funnction is called 4*number of element in array

3 Answers

Let's talk about couple of things wrong about your code.

  1. setStyle is confusing method and does two things at the same time. It, indeed, sets something but also returns a value. It is against Single Responsibility Principle and also confuses the person who takes a look at the html first. So, when I see [ngStyle]="setStyle()", I would think there is something wrong with this code, because in general setters do not return anything.
  2. You call a method from html which will result in unpredicted behaviour like the one you are having right now. It is because, Angular has this concept called Change Detection If you haven't heard of it, you should read about it. In short, whenever an event (user click, xhr request etc.) is triggered, Angular goes through your html and your component to detect if something has changed. While doing so, if there is a method within your html, angular will call it to get the result value to do some checks which may be OK for some cases if the called method does not do anything super complicated and finishes very quickly. However, with your case, it does something, it changes the color.

So, what can we do?

We need to seperate the logic of setting colors and getting colors into two different methods. Also, if possible, we should avoid calling methods from html.

I think what you are trying to do is to assign different colors to each element of the array based on previous element's color. So you can do something like following

@Component({
  selector: 'demo',
  template: `
    <div [ngStyle]="element.style" *ngFor="let element of array1"></div>
  `
})
export class DemoComponent implements OnInit {

  array1 = [];

  color = 'white';

  constructor() { }

  ngOnInit() {
    // get array from somewhere
    // this.array1 =

    this.array1.forEach(element => {
      const colorConfig = this.getNextColor();
      element.style = {
        'background-color': colorConfig.color,
        'height': '382px',
        'color': colorConfig.fontColor
      };
    });
  }

  getNextColor() {
    let fontColor;
    if (this.color === 'blue') {
      this.color = 'red';
      fontColor = 'white';
    } else if (this.color === 'red') {
      this.color = 'white';
      fontColor = 'black';
    } else if (this.color === 'white') {
      this.color = 'blue';
      fontColor = 'white';
    }

    return {
      color: this.color,
      fontColor: fontColor
    };
  }

}

It 's better in your case to use ngClass instead of ngStyle and I don't think you need to use function at all.

style

.blue {
color:blue;
background-color:red; // many css property 
}

.red {
color:red;
...
}

.white {
color:white
...
}

template

<div  [ngClass]="color" *ngFor="let element of array1" >

the class can have another property but if you still only changeing just the color you can use ngStyle

<div  [ngStyle]="{color:color}" *ngFor="let element of array1" >

stackblitz demo

Yes, it will call multiple times since you have used *ngFor and it will create multiple div element and multiple div will call ngStyle multiple times.

If you wan to call it once then you can wrap it like

<div  [ngStyle]="setStyle()">
  <ng-container *ngFor="let element of array1">
     ....
  </ng-container>
</div>

If you want to apply the ngStyle in the same div and want to repeat the same then you should put this setStyle into some variable in use it as -

public style;

ngOnInit(){
  this.style = this.setStyle(); //return the styles
}


<div  [ngStyle]="style"  *ngFor="let element of array1">
Related