When i execute the apex class in the Annonymous Window i get the output, but when i call the apex class in js . in the console i get
"{
"exceptionType": "System.JSONException",
"isUserDefinedException": false,
"message": "Malformed JSON: Expected '{' at the beginning of object",
"stackTrace": "(System Code)\nClass.ListViewLwcClass.filterCriteria: line 49, column 1\nClass.ListViewLwcClass.getTimeSheetApproval: line 4, column 1"
}" Error.
In the apex class i tried putting the queryWrapper as List to solve the issue but i get Variable query doesn't exist .
Is something wrong in the apex call in js? What is wrong with the code? Please Fix it
This is the apex code
public with sharing class ListViewLwcClass {
@AuraEnabled
public static List<Timesheet_Approval__c> getTimeSheetApproval(String objType, String listView) {
String res = filterCriteria(objType, listView);
String query = 'SELECT Id, Name, Approval_Status__c, Employee__r.Name, Customer_Engagement__r.Name, Approver__r.Name, Timesheet__r.Name FROM Timesheet_Approval__c' + (res == '' ? '' : ' WHERE ' + res);
System.debug('Res'+res);
List<Timesheet_Approval__c> ta = Database.query(query);
System.debug('Ta'+ta);
return ta;
}
@AuraEnabled(cacheable=true)
public static String getTimeSinceLastUpdate() {
Datetime lastUpdate = [SELECT LastModifiedDate FROM Timesheet_Approval__c ORDER BY LastModifiedDate DESC LIMIT 1].LastModifiedDate;
Long timeDiffInSeconds = (Datetime.now().getTime() - lastUpdate.getTime()) / 1000;
if (timeDiffInSeconds < 60) {
return 'just now';
} else if (timeDiffInSeconds < 3600) {
Integer minutes = (Integer) (timeDiffInSeconds / 60);
return minutes + ' minute' + (minutes == 1 ? '' : 's') + ' ago';
} else if (timeDiffInSeconds < 86400) {
Integer hours = (Integer) (timeDiffInSeconds / 3600);
return hours + ' hour' + (hours == 1 ? '' : 's') + ' ago';
} else {
Integer days = (Integer) (timeDiffInSeconds / 86400);
return days + ' day' + (days == 1 ? '' : 's') + ' ago';
}
}
@AuraEnabled(cacheable=true)
public static List<ListView> getListViews(String objectApiName) {
return [SELECT Id, Name, DeveloperName FROM ListView WHERE SObjectType = :objectApiName];
}
@AuraEnabled
public static String filterCriteria(String objType, String listView){
system.debug('ObjType: '+objType+'-- listView: '+listView);
Id listViewId = [SELECT id FROM ListView WHERE developerName = :listView AND sObjectType=:objType].id;
String ep = System.URL.getSalesforceBaseUrl().toExternalForm() + '/services/data/v43.0/sobjects/'+objType+'/listviews/'+listViewId+'/describe';
HttpRequest req = new HttpRequest();
req.setMethod('GET');
req.setHeader('Authorization','Bearer '+Userinfo.getSessionId());
req.setEndpoint(ep);
HttpResponse res = new Http().send(req);
system.debug('Res body: '+res.getBody());
queryWrapper qw = (queryWrapper)json.deserialize(res.getBody(), queryWrapper.class);
return (qw.query.containsIgnoreCase('WHERE')?qw.query.substringAfter('WHERE'):'');
}
public class queryWrapper{
String query{get;set;}
}
}
This is the JS code
import { LightningElement, api, wire, track } from 'lwc';
import { NavigationMixin } from 'lightning/navigation';
import getTimeSheetApproval from '@salesforce/apex/ListViewLwcClass.getTimeSheetApproval';
import minutes from '@salesforce/apex/ListViewLwcClass.getTimeSinceLastUpdate';
import getListViews from '@salesforce/apex/ListViewLwcClass.getListViews';
export default class ListView extends NavigationMixin(LightningElement) {
@track approvals = [];
@track minutesSinceLastUpdate;
@track isResizing = false;
@track totalApprovals = 0;
minWidth;
maxWidth;
col;
table;
x;
width;
@api approval; // Timesheet Approval record
@track selectedValue = 'All';
@track options = [];
loadListViews() {
getListViews({ objectApiName: 'Timesheet_Approval__c' })
.then(result => {
if (result && result.length > 0) {
this.options = [
...result.map(listView => ({
label: listView.Name,
value: listView.DeveloperName
}))
];
}
})
.catch(error => {
console.error('Error retrieving list views:', error);
});
}
handleChange(event) {
this.selectedValue = event.detail.value;
}
connectedCallback() {
setTimeout(() => {
this.fetchData();
});
this.loadListViews();
getTimeSheetApproval({ objType:'Timesheet_Approval__c', listView: this.selectedValue })
.then(result => {
let index = 0;
this.approvals = result;
this.approvals = this.approvals.map(approval => {
index += 1;
return {
...approval,
url: '/lightning/r/Timesheet_Approval__c/'+approval.Id+'/view',
sno: index,
eurl: '/lightning/r/Employee__c/'+approval.Employee__r.Id+'/view',
turl: '/lightning/r/Employee__c/'+approval.Timesheet__r.Id+'/view',
aurl: '/lightning/r/Employee__c/'+approval.Approver__r.Id+'/view',
ceurl: '/lightning/r/Employee__c/'+approval.Customer_Engagement__r.Id+'/view'
};
});
this.totalApprovals = this.approvals.length;
minutes()
.then(result => {
this.minutesSinceLastUpdate = result;
})
.catch(error => {
console.error(error);
});
})
.catch(error => {
console.error(error);
});
}
renderedCallback() {
if (this.isResizing && this.col) {
document.body.style.cursor = 'col-resize';
this.width = Math.max(this.minWidth, Math.min(this.maxWidth, this.col.offsetWidth + this.x - this.table.offsetLeft));
this.col.style.width = this.width + 'px';
} else {
document.body.style.cursor = '';
}
}
fetchData() {
this.table = this.template.querySelector('.slds-table');
if (this.table) {
const resizers = this.table.querySelectorAll('.slds-resizable__handle');
resizers.forEach((resizer) => {
resizer.addEventListener('mousedown', this.initResize.bind(this));
});
} else {
setTimeout(() => {
this.fetchData();
}, 50);
}
}
initResize(e) {
this.col = e.target.closest('th');
this.x = e.clientX;
this.width = this.col.offsetWidth;
this.minWidth = parseInt(window.getComputedStyle(this.col).minWidth) || 0;
this.maxWidth = parseInt(window.getComputedStyle(this.table).width) || 0;
this.isResizing = true;
document.addEventListener('mousemove', this.doResize.bind(this));
document.addEventListener('mouseup', this.stopResize.bind(this));
}
doResize(e) {
if (this.isResizing && this.col) {
const dx = e.clientX - this.x;
if (Math.abs(dx) >= 5) {
this.width = Math.max(this.minWidth, Math.min(this.maxWidth, this.width + dx));
this.col.style.width = this.width + 'px';
this.x = e.clientX;
}
}
}
stopResize() {
this.isResizing = false;
document.removeEventListener('mousemove', this.doResize);
document.removeEventListener('mouseup', this.stopResize);
}
}
This is html code
<template>
<!-- <lightning-card style="margin-top: 0%;"> -->
<div class="slds-page-header slds-page-header_object-home">
<div class="slds-page-header__row">
<div class="slds-page-header__col-title">
<div class="slds-media slds-no-space slds-grow">
<div class="slds-media__figure">
<span class="slds-icon_container slds-icon-standard-account">
<lightning-icon icon-name="standard:account" size="medium"></lightning-icon>
</span>
</div>
<div class="slds-media__body">
<p style="padding-bottom: 5px;" class=" slds-line-height_reset">
Timesheet Approvals
</p>
<div class="triggerLinkTextAndIconWrapper slds-page-header__name">
<div class="slds-page-header__name-title">
<h1>
<span class="triggerLinkText selectedListView slds-page-header__title">
<lightning-combobox
class="custom-combobox-container"
variant="label-hidden"
value={selectedValue}
options={options}
onchange={handleChange}>
</lightning-combobox>
</span>
</h1>
</div>
</div>
<div class="slds-p-top_small">
<p>{totalApprovals} items • Updated {minutesSinceLastUpdate} </p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="slds-scrollable_x">
<table class="slds-table slds-table_bordered slds-table_cell-buffer">
<thead>
<tr>
<th scope="col" >
<div class="slds-truncate"></div>
</th>
<th scope="col" class="slds-resizable">
<div class="slds-truncate" title="Timesheet Approver Name">Timesheet Approver Name</div>
<input type="range" min="60" max="3840" class="slds-resizable__input slds-assistive-text keyboardMode--skipArrowNavigation keyboardMode--pauseOnFocus" aria-label="Timesheet Approver Name Column Width" />
<span class="slds-resizable__handle"><span class="slds-resizable__divider"></span></span>
</th>
<th scope="col" class="slds-resizable">
<div class="slds-truncate" title="Approval Status">Approval Status</div>
<input type="range" min="60" max="3840" class="slds-resizable__input slds-assistive-text keyboardMode--skipArrowNavigation keyboardMode--pauseOnFocus" aria-label="Approval Status Column Width" />
<span class="slds-resizable__handle"><span class="slds-resizable__divider"></span></span>
</th>
<th scope="col" class="slds-resizable">
<div class="slds-truncate" title="Employee">Employee</div>
<input type="range" min="60" max="3840" class="slds-resizable__input slds-assistive-text keyboardMode--skipArrowNavigation keyboardMode--pauseOnFocus" aria-label="Employee Column Width" />
<span class="slds-resizable__handle"><span class="slds-resizable__divider"></span></span>
</th>
<th scope="col" class="slds-resizable">
<div class="slds-truncate" title="Customer Engagement">Customer Engagement</div>
<input type="range" min="60" max="3840" class="slds-resizable__input slds-assistive-text keyboardMode--skipArrowNavigation keyboardMode--pauseOnFocus" aria-label="Customer Engagement Column Width" />
<span class="slds-resizable__handle"><span class="slds-resizable__divider"></span></span>
</th>
<th scope="col" class="slds-resizable">
<div class="slds-truncate" title="Timesheet">Timesheet</div>
<input type="range" min="60" max="3840" class="slds-resizable__input slds-assistive-text keyboardMode--skipArrowNavigation keyboardMode--pauseOnFocus" aria-label="Timesheet Column Width" />
<span class="slds-resizable__handle"><span class="slds-resizable__divider"></span></span>
</th>
<th scope="col" class="slds-resizable">
<div class="slds-truncate" title="Approver">Approver</div>
<input type="range" min="60" max="3840" class="slds-resizable__input slds-assistive-text keyboardMode--skipArrowNavigation keyboardMode--pauseOnFocus" aria-label="Approver Column Width" />
<span class="slds-resizable__handle"><span class="slds-resizable__divider"></span></span>
</th>
<th scope="col" class="slds-resizable">
<div class="slds-truncate" title="Action">Action</div>
<input type="range" min="60" max="3840" class="slds-resizable__input slds-assistive-text keyboardMode--skipArrowNavigation keyboardMode--pauseOnFocus" aria-label="Action Column Width" />
<span class="slds-resizable__handle"><span class="slds-resizable__divider"></span></span>
</th>
</tr>
</thead>
<tbody>
<template for:each={approvals} for:item="approval" for:index="index">
<tr key={approval.Id}>
<td class="slds-truncate" style="width: 50px;">
{approval.sno}
</td>
<td data-label="Timesheet Approver Name" class="slds-truncate" title={approval.Name}> <a href={approval.url} target="_blank">{approval.Name}</a></td>
<td data-label="Approval Status" class="slds-truncate" title={approval.Approval_Status__c}>{approval.Approval_Status__c}</td>
<td data-label="Employee" class="slds-truncate" title={approval.Employee__r.Name}><a href={approval.eurl} target="_blank">{approval.Employee__r.Name}</a></td>
<td data-label="Customer Engagement" class="slds-truncate" title={approval.Customer_Engagement__r.Name}><a href={approval.ceurl} target="_blank">{approval.Customer_Engagement__r.Name}</a></td>
<td data-label="Created Date" class="slds-truncate" title={approval.Timesheet__r.Name}><a href={approval.turl} target="_blank">{approval.Timesheet__r.Name}</a></td>
<td data-label="Approver" class="slds-truncate" title={approval.Approver__r.Name}><a href={approval.aurl} target="_blank">{approval.Approver__r.Name}</a></td>
<td data-label="Action" class="slds-truncate">
<lightning-button label="Edit" onclick={handleEditClick} variant="neutral" data-recordid={approval.Id}></lightning-button>
</td>
</tr>
</template>
</tbody>
</table>
</div>
<!-- </lightning-card> -->
</template>