2

I am trying to specify a background color and a font color depending on a numeric value of a field. I have that working no problem. This is how it looks.

HTML:

<lightning-layout-item size="4" class={home_0_15}>
      {predictionRecord.Percentage__c}%
 </lightning-layout-item>

JS:

@track predictionRecord;


@wire(getStatistics, { recordId: '$recordId' }) wiredStatistics ({error, data}){
    if (error) {
        this.error = error;
        } else if (data) {
            this.predictionRecord = data;
            this.error = undefined;
        }
}

get home_0_15() {
        if (this.predictionRecord.Percentage__c >= 0 && this.predictionRecord.Percentage__c < 40) {
            return 'low-percentage goals-minute-contents slds-text-align_center';
        } else if (this.predictionRecord.Percentage__c >= 40 && this.predictionRecord.Percentage__c < 50) {
            return 'medium-low-percentage goals-minute-contents slds-text-align_center';
        } else if (this.predictionRecord.Percentage__c >= 50 && this.predictionRecord.Percentage__c < 70) {
            return 'medium-percentage goals-minute-contents slds-text-align_center';
        } else if (this.predictionRecord.Percentage__c >= 71) {
            return 'high-percentage goals-minute-contents slds-text-align_center';
        }
    }

CSS:

.low-percentage {background-color: #ffe9e6 !important; color:#cc2d13;}
.medium-low-percentage {background-color: #f6f7cd !important; color:#696b15;}
.medium-percentage {background-color: #72da233d !important; color:#147221;}
.high-percentage {background-color: #72da2373 !important; color:#147221;}

This works. The problem is that there are around 50 fields which I need to do the same for. This would mean 50 getters. This is not very efficient. I already went through the internet and you can't create dynamic getters as far as I understood. Is there another way to make some kind of dynamic CSS approach to solve this issue?

2 Answers 2

1

In the general sense, it's best to incorporate calculated values into the data, so you can reference it directly:

<lightning-layout-item size="4" class={predictionRecord.Percentage_Style}>
  {predictionRecord.Percentage__c}%
</lightning-layout-item>

Which you then calculate as part of loading the record:

this.predictionRecord = {...this.predictionRecord, 
  Percentage_Style: this.calculateStyle(this.predictionRecord, 'Percentage__c')
};

This would call a function like:

calculateStyle(record, field) {
  return switch(true) {
    case record[field] >= 71: return 'high-percentage goals-minute-contents slds-text-align_center';
    case record[field] >= 50: return 'medium-percentage goals-minute-contents slds-text-align_center';
    case record[field] >= 40: return 'medium-low-percentage goals-minute-contents slds-text-align_center';
    case record[field] >= 0: return 'low-percentage goals-minute-contents slds-text-align_center';
  }
}

Also, as an advanced use case, you can use Proxy. I'm going to keep this relatively simple, so I suggest you read the documentation for more information.

Here, we're going to make a fake styling system using a proxy. Each time a field is referenced, we'll transparently return the value if it exists, otherwise we'll return a fake value we calculate in real time.

this.predictionRecord = new Proxy(
  this.predictionRecord, 
  { get:(target, key) {
      if(Object.prototype.hasOwnProperty.call(target, key)) {
        return target[key];
      }
      // from before
      return calculateStyle(target, key.substring(0, key.indexOf('__Style'));
    }
  }
); 

In this manner, you can then:

<lightning-layout-item class={predictionRecord.Percentage__c__Style}>

This is a way we can apply generic logic across many properties.


Edit:

The wire handler would be the place to change the data.

@wire(getStatistics, { recordId: "$recordId" }) wiredStatistics({ error, data }) {
  if(data) {
    this.predictionRecord = {...data, 
      Percentage_Style: this.calculateStyle(this.predictionRecord, 'Percentage__c')
    };
  }
}

Or, implemented as a proxy:

@track predictionRecord;
@wire(getStatistics, { recordId: "$recordId" }) wiredStatistics({ error, data }) {
    this.predictionRecord = new Proxy(data || {}, computedProperties);
    this.error = error;
}

To make this work, add the following code after the imports, but before the class:

function calculateStyle(record, field) {
  switch (true) {
    case record[field] >= 71:
      return "high-percentage goals-minute-contents slds-text-align_center";
    case record[field] >= 50:
      return "medium-percentage goals-minute-contents slds-text-align_center";
    case record[field] >= 40:
      return "medium-low-percentage goals-minute-contents slds-text-align_center";
    case record[field] >= 0:
      return "low-percentage goals-minute-contents slds-text-align_center";
  }
}

const computedProperties = {
  get(target, key) {
    if (Object.prototype.hasOwnProperty.call(target, key)) {
      return target[key];
    }
    const fieldEnd = key.indexOf("___Style");
    if (fieldEnd > -1) {
      return calculateStyle(target, key.substring(0, fieldEnd));
    }
    return null;
  },
};

To use the proxy, just reference the field with the suffix.

<lightning-layout-item class={predictionRecord.Percentage__c___Style}>
8
  • Thanks for your reply sfdcfox! My Javascript knowledge is really basic. I do not understand the part where you calculate as part of loading the record and where to actually put that (connectedCallback?) Could you be please a bit more specific? Commented Mar 29, 2024 at 13:37
  • @eazy4me Depends on how you're receiving/loading this data, but it'll probably be in a setter, getter, or wire handler. If you edit your question to show some more code, then comment with an at-mention (like I did at the beginning of this comment), I'll be happy to revisit your question. Commented Mar 29, 2024 at 13:43
  • I added the wire function to the JS code part. Is that enough? Thanks for you help! Commented Mar 29, 2024 at 13:50
  • @eazy4me perfect. In your code, where you write this.predictionRecord = data in your wire handler, you'd perform any calculations you'd like to perform. I'm going to edit this answer in a moment. Commented Mar 29, 2024 at 14:38
  • 1
    @eazy4me No problem! Always happy to be of some help 😊 Commented Mar 29, 2024 at 15:33
0

To handle dynamic styling for multiple fields without creating a getter for each one, you can use a more generic method in your JavaScript class that computes the class based on the percentage value.

Example:

JS:

getComputedClass(event) {
  let percentage = event.target.dataset.id;
  if (percentage >= 0 && percentage < 40) {
    return 'low-percentage goals-minute-contents slds-text-align_center';
  } else if (percentage >= 40 && percentage < 50) {
   return 'medium-low-percentage goals-minute-contents slds-text-align_center';
  } else if (percentage >= 50 && percentage < 70) {
   return 'medium-percentage goals-minute-contents slds-text-align_center';
  } else if (percentage >= 71) {
   return 'high-percentage goals-minute-contents slds-text-align_center';
  }
}

HTML:

<lightning-layout-item size="4" class={getComputedClass} data-id={record.Percentage__c} key={record.Id}>
{record.Percentage__c}%
</lightning-layout-item>

This way you can add multiple fields using the same generic method. You need to write the logic into the generic method.

1
  • This is unfortunately not working. The key I can't specify as a record is loaded in the LWC. I tried it without specifying the key and no success. Commented Mar 29, 2024 at 9:23

You must log in to answer this question.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.