Hyperlink a Record in lightning:datatable

  • enter image description here

    Am trying to accomplish a POC in my project. We have a lightning Datatable using . I could generate a set of records to display on the component. But I need one column to be hyperlinked to navigate to the corresponding record when I click on them. The data table fields and object is passed dynamically at runtime either from Community Page/App Builder page/ Some Lightning container components.

    Problem:

    I couldn't figure out a way to make the first column as hyperlinked. I tried to work around by creating a formula field with HYPERLINK("/" &Id, "View Record"). But it generates this(Ref My Screenshot) on the data table in UI. If anyone can help with some workaround?

    Component:

    <aura:component controller="lightningTableController" implements="flexipage:availableForAllPageTypes,flexipage:availableForRecordHome,force:hasRecordId,force:appHostable" access="global" >
    <aura:attribute name="title" type="string" default="My Interations" />
    <aura:attribute name="recLimit" type="String" default="10" /> 
    <aura:attribute name="object" type="string" default="Case" />
    <aura:attribute name="fields" type="String" default="RecIdURL__c,FSA_BTO_Date_Of_Service__c,Subject,Type,FSA_BTO_Service_Requested__c" />   
    <aura:attribute name="sortedBy" type="string" default="FSA_BTO_Date_Of_Service__c" />
    <aura:attribute name="sortedDirection" type="string" default="DESC" />
    <aura:attribute name="mydata" type="object" />
    <aura:attribute name="mycolumn" type="object" />
    
    <aura:handler name="init" value="{!this}" action="{!c.init}" />
    
    <lightning:card title="{!v.title}" >
    
        <lightning:datatable data="{!v.mydata}" columns="{!v.mycolumn}" 
                             onsort="{!c.updateColumnSorting}" sortedBy="{!v.sortedBy}" 
                             sortedDirection="{!v.sortedDirection}" 
                             hideCheckboxColumn="true" 
                             onrowselection="{!c.getSelectedName}" keyField="Id" />
    </lightning:card>
    

    Controller.JS:

    ({
    init : function(component, event, helper) {
        helper.getLightningTableData(component);
    },
    updateColumnSorting: function (cmp, event, helper) {
        var fieldName = event.getParam('fieldName');
        var sortDirection = event.getParam('sortDirection');
        cmp.set("v.sortedBy", fieldName);
        cmp.set("v.sortedDirection", sortDirection);
        helper.sortData(cmp, fieldName, sortDirection);
    },
    getSelectedName: function (component, event) {
    
        var selectedRows = event.getParam('selectedRows');
        for (var i = 0; i < selectedRows.length; i++){
           console.log('>>>',selectedRows[i].Subject);
        }
    
      }
    })
    

    Helper.JS

    ({
    getLightningTableData : function(component) {
        var recLimit = component.get("v.recLimit");
        var sColumn = component.get("v.fields");
        var sObject = component.get("v.object");
        var action = component.get("c.getsObjectRecords");
        action.setParams({
            ObjectName : sObject,
            fieldstoget : sColumn,
            recLimit : recLimit
        });
        action.setCallback(this,function(response){
        var state = response.getState();
        if(state == 'SUCCESS'){
            var rtnValue = response.getReturnValue();
            component.set("v.mycolumn",rtnValue.tableColumn);
            component.set("v.mydata",rtnValue.tableRecord);
        }
       });
         $A.enqueueAction(action);
    },
    sortData: function (cmp, fieldName, sortDirection) {
        var data = cmp.get("v.mydata");
        var reverse = sortDirection !== 'asc';
        data.sort(this.sortBy(fieldName, reverse))
        cmp.set("v.mydata", data);
    },
    sortBy: function (field, reverse, primer) {
        var key = primer ?
            function(x) {return primer(x[field])} :
            function(x) {return x[field]};
        reverse = !reverse ? 1 : -1;
        return function (a, b) {
            return a = key(a), b = key(b), reverse * ((a > b) - (b > a));
        }
      }
    })
    

    Design:

    <design:component >
    <design:attribute name="title" label="Header Title" description="Title for the data table" />
    <design:attribute name="object" label="Object API Name" description="API Name of the Object" />
    <design:attribute name="fields" label="Fields API Name" />
    <design:attribute name="recLimit" label="Number of Records to Display" description="Limit value for SOQL"/>
    

    APEX:

    public with sharing class lightningTableController {
    
    @AuraEnabled public static lightningTableWraper getsObjectRecords(String ObjectName,String fieldstoget,Integer recLimit){     
    
        List<String> lstfieldstoget = fieldstoget.split(',');
        List<lightningTableColumnWrapper> lstTableColumn = new list<lightningTableColumnWrapper> ();
    
        DescribeSObjectResult objResult = Schema.getGlobalDescribe().get(ObjectName).getDescribe();
    
        for(String field : lstfieldstoget){
           lightningTableColumnWrapper colWrapper = new lightningTableColumnWrapper();
           DescribeFieldResult fieldResult = objResult.fields.getMap().get(field).getDescribe();
           colWrapper.label = fieldResult.getLabel();
           colWrapper.fieldName = fieldResult.getName();
           colWrapper.type = String.valueof(fieldResult.getType()).toLowerCase();
           colWrapper.sortable = true;
           lstTableColumn.add(colWrapper);
        }
        Id loggedUser = UserInfo.getUserId();
        String queryString = 'Select '+ String.escapeSingleQuotes(String.join(lstfieldstoget,','))+
                             ' from '+ String.escapeSingleQuotes(ObjectName) + ' Limit ' +recLimit;
    
        LightningTableWraper ltngTableWrapper = new LightningTableWraper();
        ltngTableWrapper.tableRecord = database.query(queryString);
        ltngTableWrapper.tableColumn = lstTableColumn;
    
        return ltngTableWrapper;
    
    }
    
    
     public class lightningTableColumnWrapper {
        @AuraEnabled
        public string label {get;set;}
        @AuraEnabled
        public String fieldName {get;set;}
        @AuraEnabled
        public string type {get;set;}
        @AuraEnabled
        public boolean sortable {get;set;}
    
    }
    
    public class lightningTableWraper{
        @AuraEnabled
        public List<sObject> tableRecord {get;Set;}
        @AuraEnabled
        public List<lightningTableColumnWrapper> tableColumn {get;set;}
    
      }
    }
    

    Share the current UI as well.

    Commenting to follow. Could be useful to me too.

    Added my screenshot. @itzmukeshy7

    Here you can take help of the `type: 'url'` and `typeAttributes: {label: { fieldName: 'linkLabel' }}` to show some useful link label of the column;

    @itzmukeshy7 This is the answer I would have given. Perhaps you might want to fill in some extra details and make it official?

  • itzmukeshy7

    itzmukeshy7 Correct answer

    3 years ago

    We can take help of the type: url and typeAttributes: {label: { fieldName: 'linkLabel' }} to show some useful link label of the column;

    Working with Column Data

    Here we have two options

    1. type possible values are(action, ..., url);
    2. typeAttributes value depends on the type option value like for url we have (label, target);

    Here is the example of the same: lightning:datatable

    Below is the example of the options:

    Type and type attributes usage

    And we can also do this type adjustment just before assigning the columns settings to the attribute in the helper(if not want to do in the Apex):

    ({
      getLightningTableData: function (component) {
        var recLimit = component.get('v.recLimit');
        var sColumn = component.get('v.fields');
        var sObject = component.get('v.object');
        var action = component.get('c.getsObjectRecords');
        action.setParams({
          ObjectName: sObject,
          fieldstoget: sColumn,
          recLimit: recLimit
        });
        action.setCallback(this, function (response) {
          var state = response.getState();
          if (state === 'SUCCESS') {
            var rtnValue = response.getReturnValue();
    
            rtnValue.tableColumn.forEach(function (column) {
              switch (column.fieldName) {
                case 'Show_Record__c':
                  column.type = 'url';
                  column['typeAttributes'] = { label: { fieldName: 'Name' } };
                  break;
    
                default:
                  break;
              }
            });
    
            component.set('v.mycolumn', rtnValue.tableColumn);
            component.set('v.mydata', rtnValue.tableRecord);
          }
        });
        $A.enqueueAction(action);
      },
      /* more methods */
    })
    

    Thanks so much @itzmukeshy7 That worked like a charm. Except that i changed my formula of the field to => "/"&id.

    Yes that I missed to mention here. :)

    @itzmukeshy7 how did you hid the Name column?

    @sebascanseco I didn't hide any column, can you please explain what you want to achieve?

    @itzmukeshy7 never mind. I missed the Account Name it's been shown in your example. This is a great explanation, but I was wondering if there's a way to hide the Account Name column as it's redundant with the first column.