Lightning-datatable:
<lightning-datatable class="slds-table_header-fixed_container slds-scrollable_x slds-border_top slds-border_left slds-border_right slds-max-medium-table_stacked slds-text-title_caps slds-text-color_weak slds-text-body_small"
key-field="Id"
onrowselection={getSelectedRecords}
sorted-by={sortBy}
sorted-direction={sortDirection}
onsort={doSorting}
data={records}
columns={columns}
draft-values={draftValues}
onsave={handleSave}
oncancel={cancelChanges}
onrowaction={handleRowAction}>
</lightning-datatable>
Lets see the Columns how we can define in variuos ways
const columns = [ { type: "url", label: PRODUCT , fieldName: "ProductUrl",initialWidth: 200, editable: false,sortable: false, wrapText: true,hideDefaultActions: true, typeAttributes: { label: { fieldName: 'Product' }, tooltip: { fieldName: 'Product' }, target: '_blank' }, }, { label: CURRENTUNITPRICE , fieldName: 'CurrentNetUnitPrice', type: 'currency',wrapText: true, hideDefaultActions: true, typeAttributes: { step: "0.001", maximumFractionDigits: 3, tooltip: { fieldName: 'Current Net Unit Price' }, }, editable: false, cellAttributes: { alignment: 'left', }, }, { label: NEWNETUNITPRICE ,fieldName: 'NewUnitPrice__c', type: 'currency', wrapText: true, hideDefaultActions: true, typeAttributes: { step: "0.001", maximumFractionDigits: 3 }, editable: { fieldName: 'isEditable' }, }, /* { label: CURRENTUNITSPECIALDISCOUNT , fieldName: 'CurrentUnitSpecialDiscount', editable: false, type: 'number',wrapText: true, hideDefaultActions: true, typeAttributes: { step: "0.00001", maximumFractionDigits: 5 }, },*/ { label: CURRENTUNITSPECIALDISCOUNT , fieldName: 'CurrentUnitSpecialDiscount', editable: false, type: 'text',wrapText: true,hideDefaultActions: true, }, { label: NEWUNITSPECIALDISCOUNT , fieldName: 'NewUnitSpecialDiscountPerKg__c', type: 'number',wrapText: true, hideDefaultActions: true, typeAttributes: { min:"0", step: ".001", maximumFractionDigits: 3 }, editable: { fieldName: 'isEditable' }, }, /* { label: 'PUR Item',fieldName: 'PURItem',type: 'text', fixedWidth: 150, editable: false, sortable: true, wrapText: true, hideDefaultActions: true, editable: false, cellAttributes: { alignment: 'left', }, }, { type: "url", label: 'PUR Item',fieldName: "PURItemUrl", fixedWidth: 150,editable: false,sortable: true, wrapText: true,hideDefaultActions: true, typeAttributes: { label: { fieldName: 'PURItem' }, tooltip: { fieldName: 'PURItem' }, target: '_blank' }, }, /* { label: 'StartDate', fieldName: 'PriceValidityStartDate', type: 'date-local', editable: false, wrapText: true, hideDefaultActions: true, typeAttributes: { day: 'numeric', month: 'numeric', year: 'numeric' } }, { type: "button", typeAttributes: { label: 'Delete', name: 'delete', title: 'Delete', disabled: false, value: 'delete', iconPosition: 'left' } }, /* { type: 'button', typeAttributes: { rowActions: actions, menuAlignment: 'right' } },*/ ];
Lets see the onrowselection how we can define
getSelectedRecords(event) {
const selectedRows = event.detail.selectedRows;
this.selectedRecords = new Array();
for (let i = 0; i < selectedRows.length; i++) {
this.selectedRecords.push(selectedRows[i]);
}
}
Lets see the onsort how we can define
sortData(fieldname, direction) {
let parseData = JSON.parse(JSON.stringify(this.purItems));
// Return the value stored in the field
let keyValue = (a) => {
return a[fieldname];
};
// cheking reverse direction
let isReverse = direction === 'asc' ? 1 : -1;
// sorting data
parseData.sort((x, y) => {
x = keyValue(x) ? keyValue(x) : ''; // handling null values
y = keyValue(y) ? keyValue(y) : '';
// sorting values based on direction
return isReverse * ((x > y) - (y > x));
});
this.purItems = parseData;
}
doSorting(event) {
this.sortBy = event.detail.fieldName;
this.sortDirection = event.detail.sortDirection;
this.sortData(this.sortBy, this.sortDirection);
if (this.sortBy == 'PURItemUrl') {
this.sortedBy = 'Price Update Request Item Number';
} else if (this.sortBy == 'ProductUrl') {
this.sortedBy = 'Product';
}
}
Lets see the onrowaction how we can define
import { NavigationMixin } from 'lightning/navigation';
handleRowAction(event) {
const actionName = event.detail.action.name;
const row = event.detail.row;
switch (actionName) {
case 'view':
this[NavigationMixin.GenerateUrl]({
type: "standard__recordPage",
attributes: {
recordId: row.Id,
actionName: 'view'
}
}).then(url => {
window.open(url, "_blank");
});
break;
case 'edit':
this[NavigationMixin.GenerateUrl]({
type: "standard__recordPage",
attributes: {
recordId: row.Id,
actionName: 'edit'
}
}).then(url => {
window.open(url, "_blank");
});
break;
case 'delete':
this.DeleteSelectedRow(row);
break;
}
} //handleRowAction Closed
Lets see the onsave how we can define
import {refreshApex} from '@salesforce/apex';
import {ShowToastEvent } from 'lightning/platformShowToastEvent';
async refresh() {
await refreshApex(this.wiredData);
}
showToastMsg(title, message, variant, mode) {
const evt = new ShowToastEvent({
title: title,
message: message,
variant: variant,
mode: mode
});
this.dispatchEvent(evt);
}
async HandelSaveToDataBase(updatedFields) {
this.isLoading = true;
var toast_title, toast_message, toast_variant;
var toast_mode = 'dismissable';
await UpsertPURItems({
records: updatedFields,
DMLType: 'Update'
})
.then(result => {
this.isLoading = false;
this.selectedRecords = new Array();
this.selectedCheckboxes= new Array();
toast_title = this.customLabel.TOASTTITLESUCCESS;
toast_message = 'Records saved';
toast_variant = 'success';
this.showToastMsg(toast_title, toast_message,
toast_variant, toast_mode);
this.draftValues = [];
return this.refresh();
}).catch(error => {
this.isLoading = false;
console.error('Error is ' + JSON.stringify(error));
toast_title = 'Error on updating records, ' +
JSON.stringify(error);
toast_message = error.body.message;
toast_variant = 'error';
this.showToastMsg(toast_title, toast_message,
toast_variant, toast_mode);
});
}
handleSave(event) {
const updatedFields = event.detail.draftValues;
console.log(event.detail.draftValues);
updatedFields.forEach((element, index) => {
if (element.hasOwnProperty('fieldAPIName1__c')) {
element.fieldAPIName1__c= element.fieldAPIName1__c- 0;
}
if (element.hasOwnProperty('fieldAPIName2__c'))
{
element.fieldAPIName2__c= (element.fieldAPIName2__c- 0);
}
});
this.HandelSaveToDataBase(updatedFields);
}
Now lets see how we can desing the standard relatedlist view in the Lightnig page using LWC
.white-rocket{
--sds-c-icon-color-foreground-default: #f3f3f3;
}
.black-rocket{
--sds-c-icon-color-foreground-default: #000000;
}
.locked-rocket{
--sds-c-icon-color-foreground-default: #dd0202b0;
}
<div class="slds-grid slds-m-left_small">
<div class="slds-col">
<div class="slds-page-header__row">
<div class="slds-page-header__col-title">
<div class="slds-media ">
<div class="slds-media__figure">
<div class="highlights-icon-container slds-avatar slds-p-left_xx-small slds-grid slds-grid_vertical-align-center" style="background-color: #904d4c">
<lightning-icon class="white-rocket" icon-name="utility:cart" alternative-text= {customLabel.PRICEUPDATEREQUESTITEMS} title= {customLabel.PRICEUPDATEREQUESTITEMS} size="small"></lightning-icon>
</div>
</div>
<div class="slds-media__body">
<div class="slds-page-header__name">
<div class="slds-page-header__name-title">
<h1>
<span class="slds-page-header__title slds-truncate" title= "Price Update Request Items" >{customLabel.PRICEUPDATEREQUESTITEMS}({recordcount})</span>
</h1>
</div>
<template if:true={isMobile}>
<template if:true={islocked}>
<lightning-icon class="slds-m-left_xx-large locked-rocket" icon-name="utility:lock" alternative-text= {customLabel.LOCKICON} title= {customLabel.LOCKICON} size="xx-small"></lightning-icon>
</template>
<template if:false={islocked}>
<lightning-icon class="slds-m-left_xx-large black-rocket" icon-name="utility:unlock" alternative-text= {customLabel.UNLOCKICON} title= {customLabel.UNLOCKICON} size="xx-small"></lightning-icon>
</template>
</template>
</div>
<div aria-live="polite" role="status">
<span class="countSortedByFilteredBy">{recordcount} items • {customLabel.SORTEDBY} {sortedBy} • </span>
</div>
</div>
</div>
</div>
<template if:true={isDesktop}>
<template if:true={islocked}>
<span class="slds-m-right_xx-small">
<lightning-icon class="locked-rocket" icon-name="utility:lock" alternative-text= {customLabel.LOCKICON} title= {customLabel.LOCKICON} size="xx-small"></lightning-icon>
</span>
</template>
<template if:false={islocked}>
<span class="slds-m-right_large">
<lightning-icon class="black-rocket" icon-name="utility:unlock" alternative-text= {customLabel.UNLOCKICON} title= {customLabel.UNLOCKICON} size="xx-small"></lightning-icon>
</span>
</template>
</template>
</div>
</div>
</div>
Now Lets see how we can design the input type like the below image using CSS part
.only-bottomBorder{
/*margin: 20px;*/
border-left: none;
border-right: none;
border-top: none;
border-bottom:1px solid #000000;
}
/* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Firefox */
input[type=number] {
-moz-appearance: textfield;
}
input:focus,
input:valid,
textarea:focus,
textarea:valid {
box-shadow: none;
outline: none;
background-position: 0 0;
}
<div class="slds-grid ">
<div class="slds-col slds-size_4-of-12">
<span>
<span style="font-weight: bold;">Euro kg: </span>
<input type="number" class="slds-m-right_small only-bottomBorder" oninput={setThreeNumberDecimalEuroKilo} value={eurokiloValue} data-field="eurokiloDataField" id="eurokiloDataField" style="width: 70px;" />
<lightning-button variant="brand" class="slds-button saveButton" label= {customLabel.SAVEEUROBUTTON} onclick={euroKiloChangeHandler} title= "Save Euro" ></lightning-button>
</span>
</div>
</div>