I've created a custom LWC datatable and I am trying to add a custom picklist in one of the columns. However, console logs are showing the picklist options and values are undefined when loading the datatable. Any help would be greatly appreciated!
Datatable.JS
import { api, LightningElement, track, wire } from 'lwc';
import getUncategorizedOnbAppDocs from '@salesforce/apex/OnboardingFileLabelRemediationController.getUncategorizedOnbAppDocs';
import { updateRecord } from 'lightning/uiRecordApi';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { refreshApex } from '@salesforce/apex';
import { getObjectInfo } from 'lightning/uiObjectInfoApi';
import { getPicklistValues } from 'lightning/uiObjectInfoApi';
import ONB_APP_DOC_OBJECT from '@salesforce/schema/onb_Onboarding_Application_Document__c';
import TYPE_FIELD from '@salesforce/schema/onb_Onboarding_Application_Document__c.Document_Type__c';
// columns
const columns = [
{
label: 'Onboarding Application Document Name',
fieldName: 'Name',
type: 'text',
editable: true,
}, {
label: 'Document Type',
fieldName: 'Document_Type__c',
type: 'PicklistColumn',
editable: false,
wrapText: true,
typeAttributes: {
options: { fieldName : 'picklistOptions' },
value: { fieldName : 'Document_Type__c'},
placeholder: 'Choose a Document Type',
context: { fieldName : 'Id'}
}
},
];
export default class OnboardingFileLabelRemediation extends LightningElement {
columns = columns;
showSpinner = false;
data = [];
onbAppDocs = [];
draftValues = [];
lastSavedData = [];
pickListOptions = [];
@wire(getObjectInfo, { objectApiName: ONB_APP_DOC_OBJECT })
onbAppDocObjectMetadata;
//Fetch picklist options
@wire(getPicklistValues, { recordTypeId: '$onbAppDocObjectMetadata.data.defaultRecordTypeId', fieldApiName: TYPE_FIELD })
onbAppDocTypePicklist ({ error, data }) {
if (data) {
this.pickListOptions = data.values;
console.log('Line49:RESULT' + JSON.stringify(this.pickListOptions));
} else if (error) {
console.log(error);
}
}
//Pass picklist options to onbAppDocs wire
@wire(getUncategorizedOnbAppDocs, { pickList: '$pickListOptions' })
onbAppDocs(result) {
this.onbAppDocs = result;
if (result.data) {
this.data = JSON.parse(JSON.stringify(result.data));
this.data.forEach(ele => {
ele.pickListOptions = this.pickListOptions;
console.log('LINE60:' + JSON.stringify(this.data));
})
this.lastSavedData = JSON.parse(JSON.stringify(this.data));
} else if (result.error) {
this.data = undefined;
}
};
updateDataValues(updateItem) {
let copyData = JSON.parse(JSON.stringify(this.data));
copyData.forEach(item => {
if (item.Id === updateItem.Id) {
for (let field in updateItem) {
item[field] = updateItem[field];
}
}
});
//write changes back to original data
this.data = [...copyData];
}
updateDraftValues(updateItem) {
let draftValueChanged = false;
let copyDraftValues = [...this.draftValues];
//store changed value to do operations
//on save. This will enable inline editing &
//show standard cancel & save button
copyDraftValues.forEach(item => {
if (item.Id === updateItem.Id) {
for (let field in updateItem) {
item[field] = updateItem[field];
}
draftValueChanged = true;
}
});
if (draftValueChanged) {
this.draftValues = [...copyDraftValues];
} else {
this.draftValues = [...copyDraftValues, updateItem];
}
}
//listener handler to get the context and data
//updates datatable
picklistChanged(event) {
event.stopPropagation();
let dataRecieved = event.detail.data;
let updatedItem = { Id: dataRecieved.context, Type: dataRecieved.value };
this.updateDraftValues(updatedItem);
this.updateDataValues(updatedItem);
}
//handler to handle cell changes & update values in draft values
handleCellChange(event) {
this.updateDraftValues(event.detail.draftValues[0]);
}
handleSave(event) {
this.showSpinner = true;
this.saveDraftValues = this.draftValues;
const recordInputs = this.saveDraftValues.slice().map(draft => {
const fields = Object.assign({}, draft);
return { fields };
});
// Updating the records using the UiRecordAPi
const promises = recordInputs.map(recordInput => updateRecord(recordInput));
Promise.all(promises).then(res => {
this.showToast('Success', 'Records Updated Successfully!', 'success', 'dismissable');
this.draftValues = [];
return this.refresh();
}).catch(error => {
console.log(error);
this.showToast('Error', 'An Error Occured!!', 'error', 'dismissable');
}).finally(() => {
this.draftValues = [];
this.showSpinner = false;
});
}
handleCancel(event) {
//remove draftValues & revert data changes
this.data = JSON.parse(JSON.stringify(this.lastSavedData));
this.draftValues = [];
}
showToast(title, message, variant, mode) {
const evt = new ShowToastEvent({
title: title,
message: message,
variant: variant,
mode: mode
});
this.dispatchEvent(evt);
}
// This function is used to refresh the table once data updated
async refresh() {
await refreshApex(this.onbAppDocs);
}
}
Datatable.HTML
<template>
<lightning-card title="Uncategorized Onboarding Application Documents" icon-name="standard:document">
<template if:true={data}></template>
<c-l-w-c-custom-datatable-type
key-field="Id"
data={data}
columns={columns}
onpicklistchanged={picklistChanged}
onvalueselect={handleSelection}
oncellchange={handleCellChange}
draft-values={draftValues}
onsave={handleSave}
oncancel={handleCancel}
hide-checkbox-column
show-row-number-column>
</c-l-w-c-custom-datatable-type>
</lightning-card>
</template>
lWCCustomDatatableType.JS (Custom Type LWC)
import LightningDatatable from 'lightning/datatable';
import PicklistColumn from './picklistColumn.html';
export default class LWCCustomDatatableType extends LightningDatatable {
static customTypes = {
PicklistColumn: {
template: PicklistColumn,
standardCellLayout: true,
editable: true,
typeAttributes: ['label', 'value', 'placeholder', 'options', 'context', 'variant', 'name']
}
}
}
pickistColumn.HTML (Custom Type LWC)
<template>
<c-picklist-column
label={typeAttributes.label}
value={typeAttributes.value}
placeholder={typeAttributes.placeholder}
options={typeAttributes.options}
context={typeAttributes.context}>
</c-picklist-column>
</template>
picklistColumn.html (Combobox LWC)
<template>
<div class="picklistSection" id="picklist">
<div if:true={showPicklist} class="picklist-section">
<lightning-combobox
name="picklist"
label={label}
value={value}
placeholder={placeholder}
options={options}
variant='label-hidden'
onchange={handleChange}
onblur={closePicklist}
class="slds-popover slds-popover_edit slds-popover__body"
dropdown-alignment="auto"></lightning-combobox>
</div>
<div if:false={showPicklist} class="slds-table_edit_container slds-is-relative">
<span class="slds-grid slds-grid_align-spread slds-cell-edit">
<span class="slds-truncate" title={value}>{value}</span>
<button data-id={context} class="slds-button slds-button_icon slds-cell-edit__button slds-m-left_x-small" tabindex="-1" title="Edit" name="tes"
onclick={handleClick} data-name="myButtonName" >
<svg class="slds-button__icon slds-button__icon_hint slds-button__icon_lock slds-button__icon_small slds-button__icon_edit slds-icon slds-icon-text-default slds-icon_xx-small"
aria-hidden="true">
<use xlink:href="/_slds/icons/utility-sprite/svg/symbols.svg?cache=9.37.1#edit"></use>
</svg>
<span class="slds-assistive-text">Edit</span>
</button>
</span>
</div>
</div>
</template>
picklistColumn.js (Combobox LWC)
import { LightningElement, api, track } from 'lwc';
export default class PicklistColumn extends LightningElement {
@api label;
@api placeholder;
@api options;
@api value;
@api context;
showPicklist = false;
connectedCallback(){
console.log("Options is "+JSON.stringify(this.options));
console.log("Value is "+JSON.stringify(this.value));
}
closePicklist() {
this.showPicklist = false;
}
handleChange(event) {
//show the selected value on UI
this.value = event.detail.value;
console.log('LINE27:Picklist Column event detail'+ JSON.stringify(event.detail));
console.log('LINE27:Picklist Column context'+ this.context);
//fire event to send context and selected value to the data table
this.dispatchEvent(new CustomEvent('picklistchanged', {
composed: true,
bubbles: true,
cancelable: true,
detail: {
data: { context: this.context, value: this.value }
}
}));
}
handleClick(event) {
this.showPicklist = true;
}
}