LWC Datatable with custom data type not rendering as supose

The question:

I have formula fields that show HTML values and I need to show them in a custom related record data table

LWC Datatable with custom data type not rendering as supose

What I have tried so far.

And to be honest, I’m frustrated right now because it’s not working for me, maybe I’m tired and I don’t see the issue or something, but I feel like I have tried everything.

Parent Component –

HTML

<template>
    <lightning-card icon-name={iconName} title={objectLabel}>
        <c-rich-datatable key-field="Id" data={tableData} columns={tableColumns} hide-checkbox-column
                      wrap-text-max-lines="3"></c-rich-datatable>
    </lightning-card>
</template>

JS

import { LightningElement, api, wire, track} from 'lwc';
import getIconName from '@salesforce/apex/ICRM_DynamicRelatedRecordsList_Ctrlr.getIconName';
import getObjectLabel from '@salesforce/apex/ICRM_DynamicRelatedRecordsList_Ctrlr.getObjectLabel';
import getFieldSet from '@salesforce/apex/ICRM_DynamicRelatedRecordsList_Ctrlr.getFieldSet';

export default class IcrmDrrl extends LightningElement {
    @api recordId;
    @api objectName = '';
    @api relatedField = '';
    @api fieldList = '';
    @api recordsToDisplay = 0;
    @track iconName = '';
    @track objectLabel = '';
    @track tableData = [];
    @track tableColumns = [];
    @track result = [];

    @wire(getIconName, { objectName: '$objectName' })
     wiredIcon({ error, data}) {
         if(data) {
            this.iconName = data;
         } else if (error) {
            this.error = error;
            this.iconName = undefined;
         }
     }

    @wire(getObjectLabel, { sobjectApiName: '$objectName' })
    wiredLabel({ error, data}) {
        if(data) {
            this.objectLabel = data;
        } else if (error) {
            this.error = error;
            this.objectLabel = undefined;
        }
    }

    @wire(getFieldSet, {
        sObjectName: '$objectName',
        listOfFields: '$fieldList',
        recordId: '$recordId',
        relationshipField: '$relatedField',
        recordsToDisplay: '$recordsToDisplay'
    }) wiredResults({error, data}) {
        if (data) {
            this.tableData = data.listData;
            this.result = data.columns;
        } else if (error) {
            this.error = error;
            this.tableData = undefined;
            this.result = undefined;
        }
    }

    connectedCallback() {
        this.result.map((col) => {
            return (col.type = "richText");
        });
        console.log(JSON.stringify(this.result));
        this.tableColumns = this.result;
        console.log(JSON.stringify(this.tableColumns));
    }

}

CustomDatatable component

HTML

<template>
</template>

JS

import LightningDatatable from "lightning/datatable";
import richTextColumnType from "./richTextColumnType.html";

/**
 * Custom component that extends LightningDatatable
 * and adds a new column type
 */
export default class richDatatable extends LightningDatatable {
    static customTypes = {
        // custom type definition
        richtext: {
            template: richTextColumnType,
            standardCellLayout: true
        }
    }
}

HTML template for customDatatable

<template>
    <!-- a template for cell. File in the myCustomDatatable directory -->
    <template if:true={wrapText}>
        <lightning-formatted-rich-text value={value} class="slds-truncate">
        </lightning-formatted-rich-text>
    </template>
    <template if:false={wrapText}>
        <lightning-formatted-rich-text value={value}>
        </lightning-formatted-rich-text>
    </template>
</template>

And still can’t make it work.

Thanks in advance to sfdcfox for helping me with the last issue.

Thanks.

The Solutions:

Below are the methods you can try. The first solution is probably the best. Try others if the first one doesn’t work. Senior developers aren’t just copying/pasting – they read the methods carefully & apply them wisely to each case.

Method 1

You’re probably missing out type attribute in the columns for the formula field. Since it’s a formula-text field. The default text column is applied.

You need to add a type attribute to the columns for that field that should be like,

  columns = [
    // standard text column
    { label: "Text Column", fieldName: "textCol", wrapText: true },
    {
      label: "Text Column",
      fieldName: "richField",
      type: "richText",
      wrapText: true,
    },
    {
      label: "Rich Text",
      fieldName: "richTextCol__c",
      type: "richText", //specify a type attribute here 
      wrapText: true,
    },
  ];

You can see a live demo here.

LWC Datatable with custom data type not rendering as supose

Once you get columns from apex. You need to change the type attribute before assigning it to the columns attribute.

  connectedCallback() {
    result.map((col) => {
      if (col.fieldName === YOUR_RICH_TEXT_FIELD) {
        return (col.type = "richText");
      }
    });
   this.columns = result;
  }

Apex Class

public with sharing class ICRM_DynamicRelatedRecordsList_Ctrlr {

    @AuraEnabled (Cacheable= true)
    public static String getIconName(String objectName) {
        String u;
        List<Schema.DescribeTabSetResult> tabSetDesc = Schema.describeTabs();
        List<Schema.DescribeTabResult> tabDesc = new List<Schema.DescribeTabResult>();
        List<Schema.DescribeIconResult> iconDesc = new List<Schema.DescribeIconResult>();

        for (Schema.DescribeTabSetResult tsr : tabSetDesc) {
            tabDesc.addAll(tsr.getTabs());
        }

        for (Schema.DescribeTabResult tr : tabDesc) {
            if (objectName == tr.getSobjectName()) {
                if (tr.isCustom() == true) {
                    iconDesc.addAll(tr.getIcons());
                } else {
                    u = 'standard:' + objectName.toLowerCase();
                }
            }
        }
        for (Schema.DescribeIconResult ir : iconDesc) {
            if (ir.getContentType() == 'image/svg+xml') {
                u = 'custom:' + ir.getUrl().substringBetween('custom/', '.svg').substringBefore('_');
                break;
            }
        }
        return u;
    }

    @AuraEnabled (Cacheable= true)
    public static String getObjectLabel(String sobjectApiName) {
        Schema.SObjectType sobjectType = Schema.getGlobalDescribe().get(sobjectApiName);
        Schema.DescribeSObjectResult sobjectDescribe = sobjectType.getDescribe();
        return sobjectDescribe.getLabelPlural();
    }

    @AuraEnabled (Cacheable= true)
    public static ColumnAndDataWrapper getFieldSet(String sObjectName, String listOfFields, Id recordId, String relationshipField, Integer recordsToDisplay) {
        ColumnAndDataWrapper cdw = new ColumnAndDataWrapper();
        List<Columns> columns = new List<Columns>();
        String fieldsToFetch = '';

        Map<String, Schema.SObjectType> gd = Schema.getGlobalDescribe();
        Schema.SObjectType ctype = gd.get(sObjectName);
        Map<String, Schema.SObjectField> fmap = ctype.getDescribe().fields.getMap();

        List<String> fieldList = listOfFields.replaceAll(' ','').split(',');

        // Generating a list of columns
        for (String f : fieldList) {
            if (f == 'Name') {
                // Uncomment and replace to allow go to record by clicking name
                // columns.add(new Columns(fmap.get(f).getDescribe().getLabel(), 'linkName', 'url'));
                columns.add(new Columns(fmap.get(f).getDescribe().getLabel(), 'Name', 'text'));
            } else {
                columns.add(new Columns(fmap.get(f).getDescribe().getLabel(), f, String.valueOf(fmap.get(f).getDescribe().getType()).toLowerCase()));
            }
            if (fieldsToFetch != '') {
                fieldsToFetch += ',';
            }
            fieldsToFetch += f;
        }

        // Get the records of requested object
        List<SObject> listData;
        if (recordsToDisplay == null) {
            listData = Database.query('SELECT Id, ' + fieldsToFetch + ' FROM ' + sObjectName + ' WHERE ' + relationshipField + ' = :recordId ');
        } else if (recordsToDisplay != null && recordsToDisplay > 0) {
            listData = Database.query('SELECT Id, ' + fieldsToFetch + ' FROM ' + sObjectName + ' WHERE ' + relationshipField + ' = :recordId LIMIT ' + recordsToDisplay);
        }
        cdw.columns = columns;
        cdw.listData = listData;
        return cdw;
    }

    public class Columns {
        @AuraEnabled public String label;
        @AuraEnabled public String fieldName;
        @AuraEnabled public String type;
        public Columns(String label, String fieldName, String type) {
            this.label = label;
            this.fieldName = fieldName;
            this.type = type;
        }
    }

    public class ColumnAndDataWrapper {
        @AuraEnabled public List<Columns> columns;
        @AuraEnabled public List<SObject> listData;
    }

}

Method 2

I found the problem, a big part of the issue was a typo in the CustomDatatable component.

export default class richDatatable extends LightningDatatable {
    static customTypes = {
        // custom type definition
     --->   richText: {
            template: richTextColumnType,
            standardCellLayout: true
        }
    }

I also refactored the main LWC JS code, by implementing this (as seen in Mr. Eric Smith DatatableV2)

    @wire(getFieldSet, {
        sObjectName: '$objectName',
        listOfFields: '$fieldList',
        recordId: '$recordId',
        relationshipField: '$relatedField',
        recordsToDisplay: '$recordsToDisplay'
    }) wiredResults({error, data}) {
        if (data) {
            this.tableData = data.listData;
    --->    data.columns.forEach(column => {
                this.result.push({
                    label: column.label,
                    fieldName: column.fieldName,
                    type: 'richText'
                });
            })
    --->    this.tableColumns = this.result;
        } else if (error) {
            this.error = error;
            this.tableData = undefined;
            this.tableColumns = undefined;
            this.result = undefined;
        }
    }

This way I was able to see the values properly formated.

Many thanks to Sachin, who took the time to help me.
And Mr. Eric Smith for sharing his knowledge and keeping it open to the world.


All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0

Leave a Comment