0

I have a select form for choosing a colour from a list of colours (each colour is an object of id, name, and hex). In the UI, the selected colour can be previewed next to the select dropdown; I am using inline styles to set the preview colour. I am binding the form to colour.id so that on load, the colour currently selected is reflected in the dropdown (as opposed to a blank or simply the first item on the dropdown). So, to get the colour's hex in the inline styling, I am using a function getColourFromId to obtain the hex value based on the selected colour's id.

My problem is: whenever I update one of my inputs, getColourFromId is triggered twice. It doesn't matter if I am updating the colour selection or some other input. When I lose focus from the input, getColourFromId is again triggered twice. I have tried to look up the docs and Google but I can't seem to find an answer as to why this is so.

Here is a stackblitz for what I am trying to do: https://stackblitz.com/edit/angular-werftf?file=src/template.html

In case the stackblitz cannot be viewed, here is the code:

// main.ts
import 'zone.js/dist/zone';
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { bootstrapApplication } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'my-app',
  standalone: true,
  imports: [CommonModule, FormsModule],
  templateUrl: './template.html',
})
export class App {
  colours = [
    {
      id: 1,
      name: 'red',
      hex: '#FF0000',
    },
    {
      id: 2,
      name: 'green',
      hex: '#00FF00',
    },
    {
      id: 3,
      name: 'blue',
      hex: '#0000FF',
    },
  ];

  selected = { ...this.colours[0] };

  name = '';

  getColourFromId(id: number) {
    console.log('id:', id);
    return this.colours.filter((colour) => colour.id === id)[0];
  }
}

bootstrapApplication(App);
<!-- template.html -->
<div
  class="colour-preview"
  [style]="{backgroundColor: getColourFromId(selected.id).hex}"
></div>
<select name="selected" id="selected" [(ngModel)]="selected.id">
  <option *ngFor="let colour of colours" [ngValue]="colour.id">
    {{colour.name}}
  </option>
</select>
<div>Hi {{name}}</div>
<input [(ngModel)]="name" />
/* global_styles.css */
.colour-preview {
  width: 24px;
  height: 24px;
  border: 1px solid black;
  margin-bottom: 8px;
}

In the stackblitz, you can see the id being logged twice. In my actual app, where I have 8 form inputs, my id is being logged 16 times instead. But in the stackblitz, it only logs twice every time even though there are 2 inputs there.

user178456
  • 27
  • 4

1 Answers1

1

This is happening because of the function getColourFromId being called in the [style]. You can create another property and use that property instead of the function.

I've modified your code below:

main.ts

import 'zone.js/dist/zone';
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { bootstrapApplication } from '@angular/platform-browser';
import { FormsModule } from '@angular/forms';

@Component({
  selector: 'my-app',
  standalone: true,
  imports: [CommonModule, FormsModule],
  templateUrl: './template.html',
})
export class App {
  currentColor;
  colours = [
    {
      id: 1,
      name: 'red',
      hex: '#FF0000',
    },
    {
      id: 2,
      name: 'green',
      hex: '#00FF00',
    },
    {
      id: 3,
      name: 'blue',
      hex: '#0000FF',
    },
  ];

  ngOnInit() {
    this.getColourFromId();
  }

  selected = { ...this.colours[0] };

  name = '';

  getColourFromId() {
    console.log('id:', this.selected.id);
    this.currentColor = this.colours.filter(
      (colour) => colour.id === this.selected.id
    )[0];
  }
}

bootstrapApplication(App);

template.html

<div class="colour-preview" [style.backgroundColor]="currentColor.hex"></div>
<select
  (change)="getColourFromId()"
  name="selected"
  id="selected"
  [(ngModel)]="selected.id"
>
  <option *ngFor="let colour of colours" [ngValue]="colour.id">
    {{colour.name}}
  </option>
</select>
<div>Hi {{name}}</div>
<input [(ngModel)]="name" />

You can check this answer for better clarity

Harshit T
  • 786
  • 4
  • 11