Friday, March 29, 2024

Calculate Values Dynamically In Lightning Web Components With Proxy

If you've ever worked with Lightning Web Components, you know that they don't support expressions, like Aura does. The usual recommendation is to copy the data and add any properties that you need to calculate. For example, one common use case is to create a record link from a record Id.

@track accountRecord; @wire(getRecord, { recordId: '$recordId', fields: FIELDS }) handleGetRecord({ error, data }) { if(data) { this.accountRecord = { ...data, accountUrl: `/${data.id}` }; } else { this.accountRecord = undefined; } this.error = error; }

This works perfectly fine, but what about the case where you need to handle dozens of values? If the only tool you have is the one above, you'll need to write at least one line per property, and you'll have to remember to add and remove properties as your markup changes. 

@track accountRecord; @wire(getRecord, { recordId: '$recordId', fields: FIELDS }) handleGetRecord({ error, data }) { if(data) { this.accountRecord = { ...data, accountUrl: `/${data.id}`, lastModifiedByIdUrl: `/${data.lastModifiedById}`, recordTypeIdUrl: `/${data.recordTypeIdUrl}` }; } else { this.accountRecord = undefined; } this.error = error; }

What if there was a better way? 

Introducing Proxy. With Proxy, you can intercept certain types of operations and react. Most developers have only met Proxy in the context of using console.log(someProperty) only to find that you can't see the data, but instead get a Proxy.

However, we can make Proxy work for us. By writing a custom proxy, we can automatically generate links for fields just by adding a prefix or suffix. Doing this requires only a few lines of code. They can even be nested on top of each other if you wanted to create a library of functions.

For our example, we're going to make a small proxy handler that will create a link given a field value. In this case, we'll say that it will always be a link to a Salesforce ID.

To do this, we just need two small adjustments. First, we need to create a proxy handler. In our case, we just need to override the get method, so we'll write this:

const linkify = { get(target, key) { // Property exists if(Object.prototype.hasOwnProperty.call(target, key)) { return target[key]; } // Property can be turned into a link: if(key.indexOf('_toLink') > -1) { return `/${target[key.substring(0, key.indexOf('_toLink'))]`; } // We could add other functions here return null; } }

Now, we just need to wrap our data with the Proxy:

@wire(getRecord, { recordId: '$recordId', fields: FIELDS }) handleGetRecord({ error, data }) { if(data) { this.accountRecord = new Proxy(data, linkify); } else { this.accountRecord = undefined; } this.error = error; }

Now, we don't need to worry about adding or removing any more JavaScript. We can just refer to these new properties in our markup:

<a href={accountRecord.id_toLink}>{accountRecord.fields.Name.value}</a>

As you can see, we can create links for any field by adding a suffix. We could do other things as well, such as calculating dates or numbers, transforming text to lower- or uppercase. We can also use the set function to perform validation or data cleanup. As we've demonstrated in this article, Proxy can be a useful tool to reduce the amount of code we have to write.

If you like this content, you can help support me in the following ways:

  • Buy me a beer
  • Paypal: brian.m.fear@gmail.com
  • CashApp: $BrianFear
  • Venmo: https://account.venmo.com/u/brianmfear
Your contributions will enable me to provide more content in the future. Comments and suggestions for future topics are welcome.