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?
    – eazy4me
    Mar 29 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.
    – sfdcfox
    Mar 29 at 13:43
  • I added the wire function to the JS code part. Is that enough? Thanks for you help!
    – eazy4me
    Mar 29 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.
    – sfdcfox
    Mar 29 at 14:38
  • 1
    @eazy4me No problem! Always happy to be of some help 😊
    – sfdcfox
    Mar 29 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.
    – eazy4me
    Mar 29 at 9:23

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .