I have implemented Custom type (custom component and custom data table) to show picklist values in LWC datatable. I have an event fired from this custom component and handling this event in my component. when pick list value is changed I want to update draft values to show 'save and cancel' and update table data. when trying to updated table data, I am receiving this error "[NoErrorObjectAvailable] Script error". Any pointers would help.
I have used below link for creating this componenet
https://live.playg.app/play/picklist-in-lightning-datatable
Here is my code:
dataTablepicklist.html
<template>
<div class="picklist-container">
<lightning-combobox name="picklist" label={label} value={value} placeholder={placeholder} options={options}
onchange={handleChange}></lightning-combobox>
datatablePicklist.js
import { LightningElement,api } from 'lwc';
export default class DatatablePicklist extends LightningElement {
@api label;
@api placeholder;
@api options;
@api value;
@api context;
handleChange(event) {
//show the selected value on UI
this.value = event.detail.value;
//fire event to send context and selected value to the data table
this.dispatchEvent(new CustomEvent('picklistchanged', {
composed: true,
bubbles: true,
detail: {
picklistData: {context: this.context,value: this.value, placeholder: this.placeholder}
}
}
));
}
}
picklist-template.html
<template>
<c-datatable-picklist label={typeAttributes.label} value={typeAttributes.value}
placeholder={typeAttributes.placeholder} options={typeAttributes.options} context={typeAttributes.context}>
</c-datatable-picklist>
</template>
customDataTable.js
import LightningDatatable from 'lightning/datatable';
import DatatablePicklistTemplate from './picklist-template.html';
import {
loadStyle
} from 'lightning/platformResourceLoader';
import CustomDataTableResource from '@salesforce/resourceUrl/CustomDataTable';
export default class CustomDataTable extends LightningDatatable {
static customTypes = {
picklist: {
template: DatatablePicklistTemplate,
typeAttributes: ['label', 'placeholder', 'options', 'value', 'context'],
},
};
constructor() {
super();
Promise.all([
loadStyle(this, CustomDataTableResource),
]).then(() => {})
}
}
Custom component to show the custom datable with picklist
HTML file
<template>
<c-custom-data-table
key-field="id"
data={productData}
columns={columns}
hide-checkbox-column="true"
show-row-number-column="true"
min-column-width="75"
draft-values={draftValues}
oncellchange={handleCellChange}
onpicklistchanged={picklistChanged}
onrowaction={handleRowAction}
>
</c-custom-data-table>
</template>
JS file-- I am getting error in updateDataValues method inside the for loop where I am trying to update loop variable with new picklist value
import { LightningElement,api,track } from 'lwc';
import createLineItems from '@salesforce/apex/AddProductsController.createLineItems';
const AUDIENCEOPTIONS = [
{value: 'Parents', label: 'Parents'},
{value: 'Kids', label: 'Kids'},
{value: 'Teens', label: 'Teens'}
];
const COLS = [
{label: 'Product', fieldName: 'name',wrapText: true},
{label:'Quantity',fieldName:'Quantity',editable: true},
{label: 'Sales Metric', fieldName: 'salesMetric', type: 'picklist',wrapText: true,typeAttributes: {
placeholder: 'Choose a value', options: [
{ label: 'CPA', value: 'CPA' },
{ label: 'CPC', value: 'CPC' },
{ label: 'CPCV', value: 'CPCV' },
{ label: 'CPI', value: 'CPI' },
{ label: 'CPM', value: 'CPM' },
{ label: 'CPVI', value: 'CPVI' },
{ label: 'Flat Rate', value: 'Flat Rate' },
{ label: 'CPE', value: 'CPE' },
]
, value: { fieldName: 'salesMetric' } // default value for picklist
, context: { fieldName: 'id' }
// binding account Id with context variable to be returned back
}},
{label:'Sales Price',fieldName:'UnitPrice',editable: true,required:true},
// {label:'Target Audience',fieldName: 'targetAudience',editable:true},
{
label:'Target Audience', fieldName: 'targetAudience', type: 'picklist',wrapText: true,typeAttributes: {
placeholder: 'Choose Target Audience', options: [
{ label: 'Parents', value: 'Parents' },
{ label: 'Kids', value: 'Kids' },
{ label: 'Teens', value: 'Teens' }
] // list of all picklist options
, value: { fieldName: 'targetAudience' } // default value for picklist
, context: { fieldName: 'id' }
// binding account Id with context variable to be returned back
}
},
{label:'Target Age',fieldName: 'targetAge',type: 'picklist',wrapText: true,typeAttributes: {
placeholder: 'Choose target Age', options:[ { label: '0-3', value: '0-3' },
{ label: '4-6', value: '4-6' },
{ label: '7-9', value: '7-9' },
{ label: '10-12', value: '10-12' },
{ label: '13-16', value: '13-16' },
{ label: 'NA', value: 'NA' },
] // list of all picklist options
, value: { fieldName: 'targetAge'} // default value for picklist
, context: { fieldName: 'id' }
// binding account Id with context variable to be returned back
}},
{label:'Target Gender',fieldName:'targetGender',type: 'picklist',wrapText: true,typeAttributes: {
placeholder: 'Choose Target Gender', options:[ { label: 'Boys', value: 'Boys' },
{ label: 'Girls', value: 'Girls' },
{ label: 'Boys & Girls', value: 'Boys & Girls' },
] // list of all picklist options
, value: { fieldName: 'targetGender'} // default value for picklist
, context: { fieldName: 'id' }
, label:{fieldName:'label'}
}
},
{label:'Device Type',fieldName:'deviceType'},
{label:'KSV Price Plan',fieldName:'ksvPricePlan'},
{label:'Start Date',fieldName: 'startDate',editable: true,type:'date',wrapText: true},
{label:'End Date',fieldName: 'endDate',editable: true,type:'date',wrapText: true},
{label:'Format',fieldName:'format'},
{label:'Media Type',fieldName:'mediaType'},
{label:'Delivery Type',fieldName:'deliveryType'},
{
type: 'button-icon',
initialWidth: 75,
typeAttributes: {
iconName:'utility:copy',
title: 'Copy'
}
},
//{label:'Frequency Cap',fieldName:'FrequencyCap',editable:true},
//{label:'Frequency Cap Period',fieldName:'FrequencyCapPeriod',editable:true}
];
export default class EditAndSaveProducts extends LightningElement {
@api recordId;
@api productAttibutes;
@track productData;
columns = COLS;
@track draftValues = [];
@api
get products(){
return this.productData;
}
set products(value){
console.log(value);
this.productData=value;
console.log(JSON.stringify(this.productData));
}
get metricOptions() {
return [
{ label: 'CPA', value: 'CPA' },
{ label: 'CPC', value: 'CPC' },
{ label: 'CPCV', value: 'CPCV' },
{ label: 'CPI', value: 'CPI' },
{ label: 'CPM', value: 'CPM' },
{ label: 'CPVI', value: 'CPVI' },
{ label: 'Flat Rate', value: 'Flat Rate' },
{ label: 'CPE', value: 'CPE' },
];
}
get deviceOptions(){
return [
{ label: 'Connected TV', value: 'CConnected TV' },
{ label: 'Desktop', value: 'Desktop' },
{ label: 'Phone', value: 'Phone' },
{ label: 'Tablet', value: 'Tablet' },
];
}
/*handleSave(event){
console.log('inside save');
} */
picklistChanged(event){
event.stopPropagation();
let dataRecieved = event.detail.picklistData;
console.log('data Recieved'+ JSON.stringify(dataRecieved));
if(dataRecieved.placeholder=='Choose Target Audience'){
var updatedItem = { id: dataRecieved.context, targetAudience: dataRecieved.value};
}
else if(dataRecieved.placeholder=='Choose target Age'){
var updatedItem = { id: dataRecieved.context, targetAge: dataRecieved.value};
}
else if(dataRecieved.placeholder=='Choose Target Gender'){
var updatedItem = { id: dataRecieved.context, targetGender: dataRecieved.value};
}
console.log('picklist changed'+JSON.stringify(updatedItem));
this.updateDraftValues(updatedItem);
this.updateDataValues(updatedItem);
}
handleRowAction(event){
console.log('inside row action');
}
handleCellChange(event) {
console.log('inside cell change');
this.updateDraftValues(event.detail.draftValues[0]);
//this.updateDataValues(event.detail.draftValues[0])
}
updateDraftValues(updateItem) {
console.log('inside draft values'+this.draftValues);
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 => {
console.log('inside loop');
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];
}
console.log('draft values'+ JSON.stringify(this.draftValues));
}
updateDataValues(updateItem) {
console.log('inside update values'+JSON.stringify(updateItem));
let copyData = [...this.productData];
console.log('copydata'+JSON.stringify(copyData))
copyData.forEach(item => {
if (item.id === updateItem.id) {
for (let field in updateItem) {
console.log('line 257'+ item['Target Audience']);
console.log('line 258'+updateItem[field]);
item[field] = updateItem[field];
}
}
});
//write changes back to original data
this.productData = [...copyData];
//console.log('data'+JSON.stringify(this.productData))
}
}