The Problem
I make my love for Salesforce Inspector well known on every team I’ve been on. I think it’s one of the best tools out there for Salesforce professionals. One particular feature that I get a huge amount of use out of is the ability to quickly view all fields on a record, whether it’s available on the page layout or not.
I’ve had a few roles, though, where I haven’t been able to use the tool for various reasons like IT security or HIPAA compliance. So I decided that I wanted to try to replicate the most useful part of the tool using Lightning Web Components, something that I’m always looking for an excuse to get better at.
Solution Designing
This was a personal project to help speed up my own workflow so I tried not get too bogged down in analysis and just start building. I started knowing only a few key features my app needed to have:
- It needs to be generic enough to use on any given sObject in Salesforce, otherwise handling for an unknown number of sObjects, custom or standard, would be unscalable
- It needs to be able to display all the fields and values on any given record in a Salesforce org
Requirement 1: It Needs to Be Generic Enough to Accept an Id of Any sObject
The great thing about the Salesforce community is that it’s unlikely that you’re the first person to ever try to solve a particular problem on the platform. The Salesforce StackExchange forum is a wealth of knowledge from people much smarter than me who have been writing about this for years. Do I know how to use a record’s id to find what type of object it is? Absolutely not. But a quick Google search of ‘how to get sObject type from id’ found me this person who does.
Requirement 2: It Needs to be Able to Display All Fields and Values for the Given Record
So if I’ve satisfied requirement 1 correctly, I know what object the record is (Account, Opportunity, My_Custom_Object__c, etc.). How can I dynamically get all the fields and values from whichever object I feed the tool? A simple SOQL query will do the trick if I know the object ahead of time.
“`SELECT FIELDS(ALL) FROM Account WHERE Id = :recordId“`
But this approach means I’ll have to write the same query for EVERY object in my org, and I’ll have to write a new query and new code any time I create a new object, not to mention mapping the value to the field name AND the field API name. That’s not scalable. Clearly this is going to be the trickiest part of the entire project.
The Build
Implementing the UI
Nothing fancy here, just need a box to take in my id, and another box to render the list of fields and their values.
Definitely take a look at the Lightning Design System documentation for more information on how to include components like buttons in HTML and use built-in CSS classes provided by Salesforce to style your components to match the ‘Salesforce’ feel without any heavy lifting.
Wiring up the Back End
Let’s take a step back and plan out our order of execution here, when we click ‘search’ the app will need to do the following:
- Use the id to determine which sObject the record is belongs to
- Dynamically retrieve all available fields to query on the sObject
- Query all of those fields for that record we initially provided
- Display all of those fields, along with their data quickly to the end user
That’s a lot of work! And to make things even trickier, each step is dependent on the last one so we need to ensure they’re queued up in the correct order otherwise everything will fail.
Asynchronous JavaScript
If you’re a less experienced JavaScript developer (like me!), your first instinct will probably be to just put all of this functionality in the same method that gets called when a user clicks ‘Search’ (it was!).
What I quickly learned (use those debug statements, people!) is that by the time the second method begins executing, the first method hasn’t yet returned anything from the server. Thankfully after a bit of Googling ‘how to chain methods in JavaScript’ I started learning about promises. The TL;DR is this: a promise creates a way to ‘chain’ together asynchronous methods in JavaScript by ‘promising’ to return a value once the asynchronous task finishes running. Specifically the newer await/async syntax proved helpful when chaining together all of the operations.
Getting the sObject Type
As I mentioned above, there are lots of smart people out there commenting on forums, let them help you on your journey! This post helped me put together a simple method leveraging some out-of-the-box functionality of the Id class in Apex that looks something like this:
Breaking this down line by line:
- The `@AuraEnabled` decorator allows this method to be accessed from a Lightning Web Component
- The method is declared and we know that we’re going to take in a string called ‘recordString’
- ‘recordString’ is converted to an Id so that we can use the Id class methods on it
- We perform a series of operations to get the name of the sObject that the Id belongs to
- Finally we return the name of the object ‘objType’ as a string to be used in our next method
Getting the Field API Names
Once we’ve successfully obtained the sObject name, let’s get the API names for all the fields on that sObject. We’re just taking our sObject and using the sObject type class to get a list of all the fields on that sObject, then sorting them so they’re in alphabetical order:
Getting the Field Labels
Now that we have our field API names, let’s go get their labels. This is very much similar to the previous method, it’s important to note that when we sorted the API names in the previous step, we ensured that we’d get the labels in alphabetical order here as well:
Getting the Field Values
This one definitely looks pretty daunting. So let’s break it down:
- We’re taking an empty string variable and for each API name in our list of API names we’re adding the API name to it.
- This way we can dynamically input that fieldsToQuery string into our query statement
- Then we use Database.query() or Dynamic SOQL, which can query even when it doesn’t know what type of sObject its looking for
- Then once we’ve got our record (sObj[0]), we just loop through our list of API names and get the value for that field!
Creating the Data to Display
To do this I created a class called FieldData, which will take in 3 strings: apiName, fieldLabel, and fieldValue. Then I just created a new FieldData instance for each field. Once I had a list of FieldData records, I serialized it and returned it to our UI for the final piece
Showing our Data
Going to the UI and iterating over each FieldValue in our table of raw data we’re able to print out something that looks like this!
Conclusion
This was something that was a lot of fun for me to build and has saved me a ton of time in my day to day role. Hope you enjoyed reading as well!