LWC Table Sort – With Example!

Lightning-Web-Component_Table_Sort
Imagine sorting this pile!

Let’s do some coding! Lightning Web Components offer a standard table called the lightning-datatable. This component has a lot of built in functions, including sorting. But what if you need a custom table and you need it to sort? I’ll show you how to implement LWC table sort. The table itself will be HTML and it will pass values back to the controller, where the sorting will be done in Javascript. You can also use these techniques outside of Salesforce since we are using pure HTML and Javascript to achieve this.

Create The Initial Component

First, create a Lightning Web Component and put it on a page. You can follow the steps in my previous post to do so. Once you have the component created, copy the following code into the HTML component to create a very basic table:

<template>
    <div>
        <table>
            <thead>
                <tr>                     
                    <th>
                        <a onclick="{sort}">
                            <div>Name</div>
                        </a>
                    </th>
                    <th>
                        <a onclick="{sort}">
                            <div>Age</div>
                        </a>
                    </th>
                    <th>
                        <a onclick="{sort}">
                            <div>Occupation</div>
                        </a>
                    </th>
                    <th>
                        <a onclick="{sort}">
                            <div>Favorite Food</div>
                        </a>                        
                    </th>
                </tr>
            </thead>
            <tbody>
                <template for:each="{People}" for:item="person">
                    <tr key="{person.Id}">                
                        <td key="{person.Id}">                                
                            {person.Name}
                        </td>
                        <td key="{person.Id}">
                            {person.Age}
                        </td>
                        <td key="{person.Id}">
                            {person.Occupation}
                        </td>
                        <td key="{person.Id}">
                            {person.FavoriteFood}
                        </td> 
                    </tr>                                                                     
                </template>
            </tbody>
        </table>
    </div>
</template>

Place this code wholesale into your HTML. This will display a table of people with the following datapoints: their name, age, occupation, and favorite food. I will have another post in the future that goes into detail on HTML table tags and what they do but, for now, just use this code for this exercise. In your Javascript file, paste the following code in the curly braces following ‘LightningElement’:

    @api People = [
        {
            Id: 1,
            Name: 'John Smith',
            Age: 21,
            Occupation: 'Farmer',
            FavoriteFood: 'Corn',                          
        },
        {
            Id: 2,
            Name: 'Michael Jones',
            Age: 35,
            Occupation: 'Banker',
            FavoriteFood: 'Sandwiches',             
        },
        {
            Id: 3,
            Name: 'Mary Larson',
            Age: 18,
            Occupation: 'Teacher',
            FavoriteFood: 'Pizza',             
        },
    ]

This code is creating the data array to feed into the table. The array is called ‘People’ and this name is referenced in the HTML portion of the component, on Line 29:

<template for:each={People} for:item="person">

Salesforce supports iterating through an array in HTML, through the syntax above. This way, we just tell the HTML what array we want to display, in this case People, and what each row will be in that array, in this person. You can name the row variable whatever you want, as long as it is in the for:item quotation marks. Save these two pieces of code and deploy this to your org. Let’s see what it looks like!

Lightning Web Component Table Made From Salesforce Records

A simple table of data! Now, lets make it a bit easier to read and then we can add the sorting. Replace Line 3 with this:

<table class='slds-table'>

And reload the page:

Lightning Web Component Table

There, that looks a bit better. slds-table is a class Salesforce supports that adds a bit of styling to a stable to make it a little more user friendly.

Table Header Click Event

Now that we have our table, let’s talk about sorting. You’ll notice that the headers for each column are hyperlinks and they are clickable. Hover your mouse over them to see the icon change from a pointer to a hand. In the HTML, the headers were wrapped in <a> tags, which designate hyperlinks. you’ll also notice that in the <a> tag for each header, we have the line:

onclick={sort}

This is a javascript event that is fired off when the object in this tag is clicked. The object, in this example, is whatever the header text is. Javascript has many events, with most of the ones used in web development starting with “on.” Javascript has onclick, onkeypress, etc., and we will use more of these in the future. For now, we have an onclick definition and the word ‘sort.’ Whatever is in the curly braces is the name of the function you are going to run when the on click event happens. Now, let’s create the sort method in our controller so sort actually does something:

    sort(e) {
    }  

Add the above to your Javascript controller. The e that is being passed in is the event information from the event. In this case, the e here is the information for the on click event. Javascript automatically creates this event for us and passes it in the method when we used the onclick={sort} syntax. With this method, we can now sort!

Implementing Lightning Web Component Table Sort

In the sort method, we need to go through the array of data we created, People, and sort by one of the columns in that array. How do we know what column someone clicked on? We have to pass it in! This is done through the event information that is being passed in. With HTML and Javascript, you can pass in data from events that you configure. In this case, we want to know what column we pass in. We need to add the line:

data-id="[column name]" 

to our <a> tags. You can pass in any information from HTML to an event by calling it:

data-[variableName]="[variableValue]"

What this does is it passes that data into the events dataset, and you can then access it in the controller. Let’s take a look. Add the data-id=”[Header Name]” to each <a> tag in our HTML:

<template>
    <div>
        <table class='slds-table'>
            <thead>
                <tr>                     
                    <th>
                        <a data-id="Name" onclick={sort}>
                            <div>Name</div>
                        </a>
                    </th>
                    <th>
                        <a data-id="Age" onclick={sort}>
                            <div>Age</div>
                        </a>
                    </th>
                    <th>
                        <a data-id="Occupation" onclick={sort}>
                            <div>Occupation</div>
                        </a>
                    </th>
                    <th>
                        <a data-id="FavoriteFood" onclick={sort}>
                            <div>Favorite Food</div>
                        </a>                        
                    </th>
                </tr>
            </thead>
            <tbody>
                <template for:each={People} for:item="person">
                    <tr key={person.Id}>                
                        <td key={person.Id}>                                
                            {person.Name}
                        </td>
                        <td key={person.Id}>
                            {person.Age}
                        </td>
                        <td key={person.Id}>
                            {person.Occupation}
                        </td>
                        <td key={person.Id}>
                            {person.FavoriteFood}
                        </td> 
                    </tr>                                                                     
                </template>
            </tbody>
        </table>
    </div>
</template>

In the sort method, we can access this value using:

e.currentTarget.dataset.id;

And that’s it! You now know what column to sort on. Now let’s do the sort. We know what column we are sorting on, so we use Javascript’s array sort method to sort our People array by the column we click on. The array sort method looks like this:

    sort(e) {
        let table = JSON.parse(JSON.stringify(this.People));
        table.sort((a,b) => 
          {return a[e.currentTarget.dataset.id] > b[e.currentTarget.dataset.id] ? 1 : -1}
        );
        this.People = table;
    }   

Sort Method

We’ve now achieved LWC table sort, but there’s a lot going on here; let’s break down the method. First, this.People needs to be written to a local variable called table, so we can call the function sort() on it. this.People is a JSON object, so we use standard methods to decode it. Now that we have our variable table, we call sort() on table. Sort() takes in a function as its parameter. We can decide this function as we see fit, but it will be a function that compares two values and determines which one has priority in the sort over the other. Let’s look at the syntax in more detail. Our function is:

(a,b) => 
          {return a[e.currentTarget.dataset.id] > b[e.currentTarget.dataset.id] ? 1 : -1}

What this is saying is, take in two items in the list, a and b, and compare if a.[Column Name] is greater than b.[Column Name]. If a is greater, return a 1. If not, return -1. That is enough for the sort method to properly determine the order. You can see we are using a ternary operator here, which has the below syntax:

[condition] ? result if true : result if false 

Also, [e.currentTarget.dataset.id] is in brackets because it is being used as a property. This is bracket notation and Javascript needs this for us to access the property of the header value we want. Now, deploy this and try clicking on the headers of our table:

Lightning Web Component Table Sort

It sorts! I clicked on Age in this case, but try it on any of the columns. And that’s it! Now, this sorts, but it’s a little clunky. First, you can’t sort in the other order. Second, there’s no indicator that of sorting being done. Let’s correct both of these issues now.

Switching Sort Order

To get the sort order to switch to descending order, we have to reverse our function in certain cases. To do this, let’s think about how any website sorts. If you click on the same column, we sort in the opposite direction. Clicking on a new column should reset the sort to go in ascending order. To do this, let’s create a variable called sortDirection and a variable called sortColumn. This way, we can store what column and direction came last:

    sortedDirection = 'asc';
    sortedColumn;

By default, sortedDirection should start in ascending order. Let’s add the logic to our sort method to use these variables:

    sort(e) {
        if(this.sortedColumn === e.currentTarget.dataset.id){
            this.sortedDirection = this.sortedDirection === 'asc' ? 'desc' : 'asc';
        }else{
            this.sortedDirection = 'asc';
        }        
        var reverse = this.sortedDirection === 'asc' ? 1 : -1;
        let table = JSON.parse(JSON.stringify(this.People));
        table.sort((a,b) => {return a[e.currentTarget.dataset.id] > b[e.currentTarget.dataset.id] ? 1 * reverse : -1 * reverse});
        this.sortedColumn = e.currentTarget.dataset.id;        
        this.People = table;
    }  

Now our table will sort in both directions! The logic here is as follows:

  1. We check if the column clicked matches the variable sortedColumn, which holds the last column clicked. If it does, we then check the sortedDirection variable, and flip it from asc to desc, or vice versa, depending on its value.
  2. If the column clicked does not match the last column clicked, we set sortedDirection to ascending.
  3. We use the value of sortedDirection to set a value called reverse to 1 (ascending) or -1 (descending).
  4. We then go through our normal sort function, but we apply the reverse value to it. It will flip the order of the sort we have defined if reverse is equal to -1.
  5. We set the People array and we store the column that we clicked into sortedColumn.

Finally, let’s add an indicator of sort order. This gets a bit tricky. There are a few ways to do this, but let’s add an arrow to the column conditionally and delete an arrow from a column if it already exists when we click on sort. Add this code to the end of the sort method:

if(e.currentTarget.dataset.id){

    let existingIcon = this.template.querySelectorAll('img[id="sorticon"]');
    if(existingIcon[0]){existingIcon[0].parentNode.removeChild(existingIcon[0]);}

    let nodes = this.template.querySelectorAll('a[data-id="' + e.currentTarget.dataset.id +'"]')
    if(this.sortedDirection === 'asc'){icon.setAttribute('src', Images + "/images/icons/arrowup.png");}
    if(this.sortedDirection === 'desc'){icon.setAttribute('src',  Images + "/images/icons/arrowdown.png");}
    icon.setAttribute('id', 'sorticon');
    if(nodes[0]){nodes[0].children[0].appendChild(icon);}
}

A few things to note here:

  1. You need to upload a static resource file and you need it to import it into your Javascript file as so: import Images from “@salesforce/resourceUrl/Images”; You can find out how to upload a static resource here.
  2. You need to call your image whatever you reference and follow that file path. In my case, I have an images –> icons –> arrowup/down.png file in my static resource. Make your file name and path match what you reference.

Once you have the above, the code itself is pretty simple. First, we use a querySelectorAll to query the template and find an img tag with the id sorticon. We then delete it. Then, we find the node we clicked on through another querySelectorAll and we query for an a tag that has the data-id we pass in. We then build an img tag and set the icon to be up or down based on what the value of sortedDirection is. We also give it an id of sorticon so it can be deleted if another column is clicked on or the direction changes. Finally, we insert it to the tag we clicked on!

With the above, you have now implemented LWC table sort. Having a table that sorts is great start. You can now add other features, such as search.

Create And View Lightning Web Components

Create-A-Lightning-Web-Component-And-View-It-Banner

Before we dig into the meatier topics on this blog, let’s get a basic step out of the way. A lot of the things we will work with are Lightning components, Aura or LWC, and I will be providing sample code for you to use if you want to follow along. To see the code in action, you will usually have to create and view Lightning Web Components. Let’s learn how to do that now!

Let’s first start with a Lightning Web Component. Go to Visual Studio Code and open up a project connected to your Salesforce org. Then open the Command Palette (Ctrl + Shift + P) and type in and choose ‘SFDX: Create Lightning Web Component:’

VSCode Create LWC

Enter a name for this component (I chose SortedTable for this exercise) and choose force-app\main\default\lwc as the directory to place it in (this should be the first value in the list):

VSCode LWC Name

Once you have made the component, take a look at it in the file tree. Open up the filepath force-app\main\default\lwc and you will see a folder for the component you just created. Open that up to the see files inside:

VSCode Lightning Web Component File

All LWC components are made up of an HTML file and a Javascript file (.html and .js extensions, respectively). The .js-meta.xml file is a Salesforce configuration file needed to recognize this new component. It is automatically created for you through the Command Pallette function you used when you initially made the component. The .js-meta.xml file for a component needs to have the following lines for it to be added into a page:

<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="SortedTable">
    <apiVersion>46.0</apiVersion>
    <isExposed>true</isExposed>
    <targets>
        <target>lightning__AppPage</target>
        <target>lightning__RecordPage</target>
        <target>lightning__HomePage</target>
    </targets>    
</LightningComponentBundle>

Make the edits to the .js-meta.xml and right-click on your component folder. Choose ‘SFDX: Deploy Source To Org’ to send it over to your Salesforce instance!

VSCode LWC XML

Now that the component is in Salesforce, let’s add it to a page. Go to your Salesforce org and click on the gear icon in the upper right corner Choose ‘Setup.’ On the setup screen, use the Search bar in the upper left and type in ‘Lightning App Builder.’ You will see the list of options filter down to that choice. Select it and click on the New button near the center of the screen. Choose to create an App Page:

VSCode App Builder

Give it whatever name you want (I chose Sorted Table again) and select ‘One Region:’

VSCode Lightning Page

Now, you can add a component to this page! Select your component from the left hand menu under custom and drag it to your page:

VSCode View LWC

If you do not see your custom component, you may see a message that says a custom domain is required to use custom components. If so, click on the link portion of that message and follow the instructions to create and activate your domain. more information can be found here, but you will essentially have to pick a name, confirm it through email, and then activate your domain through the email link.

Once your component is on the page, click ‘Save’ and click ‘Activate’ on the popup. You will then see a popup with three tabs. Navigate to the second one and called ‘Lightning Experience’ and click an option in the left-hand menu (in this case I chose Sales). Then, click ‘Add page to app’ in the right-hand menu:

VSCode Tab Setup

Your component will now appear in whatever app you selected. Let’s see it in action! Click ‘Save’ in the popup to finalize this and click ‘Save’ one more time on the Lightning App Builder screen. Then, click the ‘Back’ icon in the upper right corner to go back to Setup. From Setup, click on the ‘App Launcher’ icon and choose Sales:

VSCode App Builder
VSCode View Component

And Sorted Table is in the tab list at the top! There’s not much to see yet, if you click on it, but we will add code to it. You can use these steps to create and view lightning web components for any project you have.

Create and View Lightning Web Component

VSCode Setup For Salesforce Developement

You’re ready to start coding! You may have a task you want to automate or a project in mind but first, how do you get started? I use Visual Studio Code (VSCode) to do my coding when I’m programming in Apex, Salesforce’s custom programming language. Salesforce also endorses using Visual Studio; they even have a Trailhead dedicated to it. Let’s learn how to get VSCode setup for Salesforce development.

Configuring Salesforce Packages

First things first: let’s download Visual Studio Code. You can get the latest version here. Run the executable and then open up Visual Studio Code. You will then be greeted to this:

VSCode homepage

Click on the lowest icon on the left hand sidebar for Extensions:

VScode Extensions

There are a variety of extensions you can download for Salesforce specifically, like the Apex extension, the Apex debuggers, etc. but the two we will install are the Salesforce Extension Pack and Salesforce CLI integration. Search for them in the search bar and click Install. From here, you now have access to a few commands in the Command Palette. The Command Palette is a way for you to run commands that are built into Visual Studio Code natively or from extensions.

Connecting To A Salesforce Instance

Now that Visual Studio code is up and running, you need to connect it to the Salesforce org you are working out of. Click on ‘View’ then select ‘Command Palette’ (or press Ctrl + Shift + P). Then type ‘SFDX’ and you will see prepopulated commands. Choose ‘SFDX: Create Project with Manifest’.

VSCode SFDX Commands

This will kickoff some background processes to start connecting your org. You will first be asked to enter your project name:

VSCode Connecting to SF Org

Windows Explorer will open and ask you to specify the folder the project files will be stored locally:

VSCode Local Directory Setup

Make a folder in a directory you keep projects in and then highlight it. Select ‘Create Project.’ Visual Studio Code will do a little processing and then you will have a skeleton project! If you navigate using the file tree on the left, you will see an option called ‘manifest.’ Click on it and you will see a single file called ‘package.xml.’

VSCode package.xml

This file is what Visual Studio Code uses to talk to the Salesforce org and pull down the metadata locally. It has the most commonly used files like ApexClass and ApexPage prepopulated, but any other metadata you want to pull down aside from these can be added by simply adding the line(s):

<types>
  <members>*</members>
  <name>{API name for metadata}</name>
</types>

The asterik in the members attribute is a wildcard and it means you are pulling all files of this metadata type. You can do this if you want everything, or you can specify only pulling down certain values by deliberately naming them or using the wildcard character to select certain files. Say I was coding a project and I named all the classes beginning with the word ‘Ali.’ I could pull all these down by having this in my members tag:

<types>
  <members>Ali*</members>
  <name>ApexClass</name>
</types>

This would only pull down Apex Classes that start with ‘Ali’!

Pull From Salesforce Instance

Now that you have your package.xml and your Visual Studio Code project made, how do you connect to an org and get the data? Go to the Command Palette again and type in ‘SFDX.’ Select the option ‘SFDX: Authorize An Org’:

VSCode SFDX Command Palette 1

From here, select what type of org this is (Sandbox, Production, etc.), specify a name for the org, and a browser will open and direct you to login. Enter your credentials and allow Salesforce CLI Integration access to your org.

Salesforce Org Authorization

Now, when you right-click on the package.xml file in Visual Studio Code, you can choose the command ‘SFDX: Retrieve Source in Manfiest from Org’:

VSCode Retrieve From Manifest

Click on it and give it a shot! When it’s done, you will see all the files you specified in the package.xml in your local project:

VSCode Salesforce Development

From here, you’re ready to code! You can now open your files and use Visual Studio Code as an IDE. When you want to upload a file back to the server, right click on it and select ‘SFDX: Deploy Source to Org’:

VSCode Deploy Source To Org

Visual Studio Code offers a lot of quality-of-life features on top of being a pretty robust text editor and file explorer. It can pre-populate commands and keywords that are used by Apex and other programming languages and can even give you tips on what methods need to work if you hover over them as you code and compile. Now that you’ve got VSCode setup for Salesforce development, the sky’s the limit. To get started, why not try creating a Lightning Web Component? Thanks for reading!

The Birth Of This Blog

Hi everyone! My name is Ali and I am creating this blog to share tips and tricks regarding coding. I am a professional developer who works primarily in Salesforce. I cannot count the amount of times I have Googled how to do something when I was coding, from declaring and filling an array to sending an email. I want to write this blog to share the things I have learned and to catalog the simple mechanics of coding that I have always looked up. Hopefully, with these building blocks in place, you can learn something from my experiences!

I am going to focus mostly on Salesforce and Apex development, but I also code in Visual Basic (Excel macros), Python, and databasing. I am also going to cover some of the tools commonly used to complete a project. This way, you won’t have to do some of the digging I did to get your IDE up and running or make an API call.