Hey Everyone,
Welcome again. In this blog post, we are going to learn how we can add hyperlink in datatable and how to add custom icons based on some conditions in lightning datatable
Use Case: –
Business wants to display the list of top 10 cases in a datatable. There are few catches here that are given below
- CaseNumber & Subject Field must be hyperlink and when click on those it should redirect to case detail page.
- Contact Name & Account Name field also should be hyperlink field and clicking on it should redirect to contact or account record.
- An icon should be displayed left to priority field and icon should be changed based on priority.
Now, as we have got the use case. Let’s see what all it will take to develop.
- An Apex class
- Lightning Web Component
Before we directly jump into the final outcome, we will break the requirement into multiple steps. So, let’s create the apex class first.
Use below code and Name it as CaseLWCService
public with sharing class CaseLWCService {
@AuraEnabled
public static List<Case> fetchCases(){
return [SELECT Id, CaseNumber, Subject, Description, AccountId, Account.Name, ContactId,
Contact.Name, Status, Priority
FROM CASE
LIMIT 10];
}
}
We have got our apex class which will return the Top10 Case records.
Now, let’s develop the component which will be using Lightning:datatable for displaying the records. Use below code for .html file
<template>
<lightning-card variant="Narrow" title="Case List" icon-name="standard:case">
<div class="slds-m-around_small">
<lightning-datatable
key-field="id"
data={result}
show-row-number-column
hide-checkbox-column
columns={columnsList}
onrowaction={handleRowAction}>
</lightning-datatable>
</div>
</lightning-card>
</template>
We have got the UI part, however we need to have the associated JavaScript class so that we can pull the data from Apex Class and that data can be displayed into component. Below is the code for the JS Class.
import { LightningElement, wire, api, track } from 'lwc';
import fetchCases from '@salesforce/apex/CaseLWCService.fetchCases';
const columns = [
{ label: 'CaseNumber', fieldName: 'CaseNumber' },
{ label: 'Subject', fieldName: 'Subject', wrapText: true},
{ label: 'Status', fieldName: 'Status' },
{ label: 'Priority', fieldName: 'Priority' },
{ label: 'Contact', fieldName: 'ContactName', wrapText: true },
{ label: 'Account', fieldName: 'AccountName', wrapText: true }
];
export default class CaseDatatable extends LightningElement {
@api result;
@track error;
columnsList = columns;
connectedCallback(){
this.getAllCaseDetails();
}
getAllCaseDetails(){
fetchCases()
.then(data => {
/* Iterate with Each record and check if the Case is Associated with Account or Contact
then get the Name and display into datatable
*/
data.forEach(caseRec => {
if(caseRec.ContactId){
caseRec.ContactName = caseRec.Contact.Name;
}
if(caseRec.AccountId){
caseRec.AccountName = caseRec.Account.Name;
}
});
this.result = data;
window.console.log(' data ', data);
this.error = undefined;
})
.catch(error => {
this.error = error;
window.console.log(' error ', error);
this.result = undefined;
});
}
handleRowAction(){
}
}
and below is the code for meta file
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>48.0</apiVersion>
<isExposed>true</isExposed>
<masterLabel>Case Details</masterLabel>
<targets>
<target>lightning__RecordPage</target>
<target>lightning__AppPage</target>
<target>lightning__HomePage</target>
<target>lightningCommunity__Page</target>
<target>lightningCommunity__Default</target>
</targets>
</LightningComponentBundle>
We have developed the component and displayed the case list into datatable. However, we are still remaining with few point. If you will see the output of the above component will look like below
If you notice the above screenshot, there is no hyperlink shown for any of the fields which were mentioned in the use case.
Let’s modify the columns of datatable to display the link.
We are going to use same column which is CaseNumber and Subject. To display the url what we need to do is specify the type for the column like below
{ label: 'CaseNumber', fieldName: 'CaseNumber', type:'url' },
However, doing this will not work. What we need to do is to add some attributes in the same column under typeAttributes so that we can specify the text which we wanted to display. See code below, inside typeAttributes we can specify the target as well and many more. Learn Here
typeAttributes: {
label: { fieldName: 'CaseNumber' },
target : '_blank'
}
Now, if we merge the code it will look like below
{
label: 'CaseNumber', fieldName: 'CaseNumber', type:'url',
typeAttributes: {
label: {
fieldName: 'CaseNumber'
},
target : '_blank'
}
},
We have prepared the column and there is one more thing remaining which is the actual URL. As if you noticed on the above code we are using CaseNumber in both places and the record details url look like below
https://+host+/+recordId
So, we have to prepare the URL and a new field so that we can use that new field in place of CaseNumber in the first place of fieldName: ‘CaseNumber’, type:’url’,
We will follow the same approach for the rest 3 fields ( Subject, Contact Name & Account Name). That means we will be needing 3 New fields which will contain the record detail page Link.
Now, here is the update code for JavaScript Class with URL/HyperLink in Datatable
import { LightningElement, wire, api, track } from 'lwc';
import fetchCases from '@salesforce/apex/CaseLWCService.fetchCases';
const columns = [
{
label: 'CaseNumber', fieldName: 'caseUrl', type:'url',
typeAttributes: {
label: {
fieldName: 'CaseNumber'
},
target : '_blank'
}
},
{
label: 'Subject', fieldName: 'caseUrl', wrapText: true,
type: 'url',
typeAttributes: {
label: {
fieldName: 'Subject'
},
target : '_blank'
}
},
{ label: 'Status', fieldName: 'Status' },
{ label: 'Priority', fieldName: 'Priority' },
{
label: 'Contact', fieldName: 'ContactUrl', wrapText: true,
type: 'url',
typeAttributes: {
label: {
fieldName: 'ContactName'
},
target : '_blank'
}
},
{
label: 'Account', fieldName: 'AccountUrl', wrapText: true,
type: 'url',
typeAttributes: {
label: {
fieldName: 'AccountName'
},
target : '_blank'
}
}
];
export default class CaseDatatable extends LightningElement {
@api result;
@track error;
columnsList = columns;
connectedCallback(){
this.getAllCaseDetails();
}
getAllCaseDetails(){
fetchCases()
.then(data => {
/* Iterate with Each record and check if the Case is Associated with Account or Contact
then get the Name and display into datatable
*/
/* Prepare the Org Host */
let baseUrl = 'https://'+location.host+'/';
data.forEach(caseRec => {
caseRec.caseUrl = baseUrl+caseRec.Id;
if(caseRec.ContactId){
caseRec.ContactName = caseRec.Contact.Name;
/* Prepare Contact Detail Page Url */
caseRec.ContactUrl = baseUrl+caseRec.ContactId;
}
if(caseRec.AccountId){
caseRec.AccountName = caseRec.Account.Name;
/* Prepare Account Detail Page Url */
caseRec.AccountUrl = baseUrl+caseRec.AccountId;
}
});
this.result = data;
window.console.log(' data ', data);
this.error = undefined;
})
.catch(error => {
this.error = error;
window.console.log(' error ', error);
this.result = undefined;
});
}
handleRowAction(){
}
}
If you will preview the code, you will see the screen like below
We are done with 75% of the requirement however still we need to display the icons next to Priority based on priority. For this, we need to use cellAttributes property of the datatable column instead of typeattributes.
Let;s see how to display the icon and we can get the icons from here
{
label: 'Priority', fieldName: 'Priority',
cellAttributes: {
iconName: 'utility:sentiment_negative',
iconAlternativeText: 'Priority'
}
},
If you have noticed, we are using icon name which is static and will display the same icon. So to display the icon dynamically we need to generate the icon in JS and use like below
{
label: 'Priority', fieldName: 'Priority',
cellAttributes:{
iconName: {
fieldName: 'priorityIcon'
},
iconPosition: 'left',
iconAlternativeText: 'Priority Icon'
}
},
Below is the complete code for the blog
If you will preview the code you will see the output like below
Thanks for Reading. Sharing is Caring 🙂
If you have any questions or suggestions, please feel free to reach out to me.
Hello Team,
Thank you for nice blog. I learnt something out of it. I tried to modify for Account sObject but once i add to Builder I am not able to see records, can you please where I am missing:
Class Logic:
@AuraEnabled(cacheable=true)
public static List getAccountList(){
return [select id, Name, AccountNumber, Phone, Rating from Account
LIMIT 5];
}
JS file:
import { LightningElement, api, track } from ‘lwc’;
import getAccountList from ‘@salesforce/apex/AccountController.getAccountList’;
import ACCOUNTNUMBER_FIELD from ‘@salesforce/schema/Account.AccountNumber’;
import PHONE_FIELD from ‘@salesforce/schema/Account.Phone’;
import RATING_FIELD from ‘@salesforce/schema/Account.Rating’;
const COLUMNS = [
{ label: 'Account', fieldName: 'AccountUrl', wrapText: true,
type: 'url',
typeAttributes: {
label: {
fieldName: 'AccountName'
},
target : '_blank'
}
},
{ label: 'Account Number', fieldName: ACCOUNTNUMBER_FIELD.fieldApiName, type: 'text' },
{ label: 'Phone', fieldName: PHONE_FIELD.fieldApiName, type: 'Phone' },
{ label: 'Rating', fieldName: RATING_FIELD.fieldApiName, type: 'Picklist' }
];
export default class retrieveRecord extends LightningElement() {
@api result;
@track error;
columnsList = COLUMNS;
connectedCallback(){
this.getAllCaseDetails();
}
getAllCaseDetails(){
getAccountList()
.then(data => {
/* Iterate with Each record and check if the Case is Associated with Account or Contact
then get the Name and display into datatable
*/
/* Prepare the Org Host */
let baseUrl = 'https://'+location.host+'/';
data.forEach(accRec => {
accRec.AccountUrl = baseUrl+accRec.Id;
if(accRec.Id){
accRec.AccountName = accRec.AccountName;
/* Prepare Account Detail Page Url */
accRec.AccountUrl = baseUrl+accRec.Id;
}
});
this.result = data;
window.console.log(' data ', data);
this.error = undefined;
})
.catch(error => {
this.error = error;
window.console.log(' error ', error);
this.result = undefined;
});
}
handleRowAction(){
}
}
HTML:
meta.xml:
49.0
true
lightning__AppPage
lightning__RecordPage
lightning__HomePage
Please advise what went wrong and how to correct at the earliest.
Regards,
HS
Hello there,
in conjunction to my initial post, I have printed the error log in console and got below stacktrace:
error TypeError: Cannot add property AccountUrl, object is not extensible
at eval (retrieveRecord.js:4)
at Array.forEach ()
at eval (retrieveRecord.js:4)
Please advise how to correct.
Thanks.
HS
Hi,
You are getting this error because @wire method is readonly and you are trying to add property on the result that’s why you are getting the error. Try to call your method from the connectedCallback and the doo the same.
Hi Anonymous and SFDC Panther,
I got the error message “object is not extensible” but it was because the JS object is not extensible. I created a deep copy of the data array and then did the foreach loop on the new copy, then assigned it back to the data array and it worked.
https://stackoverflow.com/questions/45798885/object-is-not-extensible-error-when-creating-new-attribute-for-array-of-objects
let newData = data.map((item) =>
Object.assign({}, item, {selected:false})
)
Can we change ICON size by using default slds class?
You can try to use the class attribute and see if that works.
I tried class attribute for cell but it didn’t make any change
In that case, you need to do hit and trail
Hi Team,
Is this available in lightning components.
Kindly let me know if it is available above requirement in lightning.
lightning:datatable is in salesforce lightning only.OR Are you looking for something else?
I’m looking for in aura components instead of LWC. please help me with lighting components code
The code is there you just need to make some modifications on the JavaScript side. I can not provide the code but you can write it and then I can help if there is something you got stuck to.
same requirement I want to apply in components instead of LWC. could please help me on this.
Its worked but if we want to display only 5 records at a time and wants to have a view all button to display all records in a window then how to implement this?
In that case, you need to implement the pagination to display the 5 records. And to display view all you have to develop your own piece of logic as displaying all 5 records in one window is not great as per me but your requirement can be different.
Hi, if I am calling this component from another component and passing the recordid then no data is coming in UI. could you pls tell me how to solve this?
Hello,
Have you modified the component code? As in my code, I have not used any filter based on Id.
Yes I have added one variable @api caseId in this and calling this component from another component with the caseid. In apex filtering cases based upon id.
data table JS:
@api caseId
connectedcallback(){this.getAllCaseDetails();}
getAllCaseDetails(){
console.log(‘case id >>’+this.caseId); ///is coming as undefined
fetchCases({Cased:this.caseId})
.then(data =>{
console.log(‘data >>’+data);
Other component from where i am calling data table:
You have to pass the value for the caseId variable.
passing the caseid but still the case id is not coming when it is in connectedcallback method
Hi, This is not working for me, do we need to create caseurl and AccountUrl etc., fields in respective objects? In my case I have a dropped down which have all the sobjects and on change of combobox I am forming the columns as below:
[{“label”:”Id”,”fieldName”:”Id”,”type”:”text”},{“label”:”Name”,”fieldName”:”recordurl”,”type”:”url”,”typeAttributes”:{“label”:{“fieldName”:”Name”},”target”:”_self”},”sortable”:true}]
and used the same code as you using the foreach loop assigned the url to recordurl
You do not need to create any field on Account or case Object. You need to prepare those fields inside your JavaScript Method. If you are following the way I did and doing it correctly you will be able to get it correct.
TypeError: Cannot add property oppUrl, object is not extensible….. its showing tis error
You have made your method as cacheable=true. Remove your annotation “cacheable=true”
Hi Amit, I have a scenario where I want to show Row Action button under lightning data table based on some condition.
means like if case. Priority==”High” then only Row Action button(View Details) under table should be visible else it will be false in LWC.
Hello Tarun,
Yes, you can do that are you getting any issues?
Thanks for sharing .. I have faced issues with url opens new tab whatever used either _blank/_self/_top/_parent .. have you experienced same and any solution? I use case is to open in same tab.
Unfortunately this is the standard behaviour
Can we do by JavaScript event or navigation?
You can give it a try
How to make the url field land on a specific url ? by placing the url into target ? like target: “www.google.com” ?
I tried this but its not going to the google.com.
My field value is “member xyz”. after clicking on it its redirecting to
https://member%20xyz%20template
You have to prepare the data accordingly the ways we have done for CaseNumber