You need to sign in to do that
Don't have an account?
Kent Lichty
How to pass a class wrapper with Identifier from LWC datatable to Apex on Save?
I am fairly new to Salesforce and really new to learning about LWC, and my organization has tasked me with what I think is a difficult challenge. Because sometimes the (poor) definition of sObjects does NOT make them conducive to user maintenance, I have been tasked to develop a maintenance application (in the form of an LWC datatable) which makes it easier for users to enter/change prices (expressed in 6 different currencies) for a given product. In order to do this I needed to create a class wrapper which combines properties from a Product sObject and a Price sObject. Then I need to be able to SAVE those changed prices back into the appropriate Price record, and that is the difficult part with which I am struggling. But I would think that this would be a common use case.
And while there is a LOT of information about DISPLAYING class wrappers in a datatable (which is quite simple) there is virtually no information about sending the list of modified properties back to an imperative Apex program which could then do the record updating, and that is what I am hoping that somebody has figured out how to do.
I think I am very close to being able to achieve this, and am hoping that somebody can help me get to the finish line. Here is the approach I am taking:
For what it’s worth, here is my wrapper class which is keyed by a “product” code and then has the associated prices in 6 different currencies, along with some other information about the product.
public String product{get;set;}
public String productFamily {get;set;}
public String productLine {get;set;}
public String productSubLine {get;set;}
public String productCategory {get;set;}
public Decimal priceCad {get;set;
public Decimal priceEur {get;set;}
public Decimal priceGbp {get;set;}
public Decimal priceInr {get;set;}
public Decimal priceJpy {get;set;}
public Decimal priceUsd {get;set;}
And here is a fragment of my displayed list just to amplify the concept; it just shows 2 currency amounts instead of all 6 just to make it clearer.
So I just want to use the same “draft values” approach that is standard for the datatable component, as below:
And here is the standard “Save” function (from another project; NOT this one) which I am sure most of you have seen, and which uses the uiRecordApi to implement, without any Apex call.
handleSave(event) {
const recordInputs = event.detail.draftValues.slice().map(draft => {
const fields = Object.assign({}, draft);
return { fields };
});
But in my application I know that I need to imperatively call my Apex class to handle this update, and I can do that. I am currently only passing back the JSONified values of the “draftValues” and the entire list itself, just to see how that works:
handleSave(event) {
var draftValuesStr = JSON.stringify(event.detail.draftValues);
var wrapList = JSON.stringify(this.pricesList);
updatePriceRecords({updateObjStr: draftValuesStr, wrapList: wrapList});
}
And this does bring back the “draft” values perfectly for me, as you can see below:
[{"priceUsd":"456.00","priceEur":"765.67","Id":"row-3"}]
And my Apex could handle the price updates if ONLY it had some unique ID (like the product number, in my case), so that is what I am asking how to do. All the string contains as an ‘ID’ is the row ID, which is not very helpful. I know that I can bring back the ENTIRE list, and then be able to associate the row ID with the appropriate record in the list and get the product number that way, but that is clearly a horribly inefficient idea, and there has got to be a better way.
I also considered somehow persisting my list into a CACHE (like a user setting?) so I could retrieve the original list that way, but that does not sound like a good idea either.
Also, I am thinking that I could somehow iterate through the JSONified draft values and insert the product ID appropriately into that list, but I am not sure how I would go about grabbing the product ID out of selected draft record.
If anybody could help me out with this I would really appreciate it. It seems to me that this would be a very common use case out there.
Thanks very much.
And while there is a LOT of information about DISPLAYING class wrappers in a datatable (which is quite simple) there is virtually no information about sending the list of modified properties back to an imperative Apex program which could then do the record updating, and that is what I am hoping that somebody has figured out how to do.
I think I am very close to being able to achieve this, and am hoping that somebody can help me get to the finish line. Here is the approach I am taking:
For what it’s worth, here is my wrapper class which is keyed by a “product” code and then has the associated prices in 6 different currencies, along with some other information about the product.
public String product{get;set;}
public String productFamily {get;set;}
public String productLine {get;set;}
public String productSubLine {get;set;}
public String productCategory {get;set;}
public Decimal priceCad {get;set;
public Decimal priceEur {get;set;}
public Decimal priceGbp {get;set;}
public Decimal priceInr {get;set;}
public Decimal priceJpy {get;set;}
public Decimal priceUsd {get;set;}
And here is a fragment of my displayed list just to amplify the concept; it just shows 2 currency amounts instead of all 6 just to make it clearer.
So I just want to use the same “draft values” approach that is standard for the datatable component, as below:
And here is the standard “Save” function (from another project; NOT this one) which I am sure most of you have seen, and which uses the uiRecordApi to implement, without any Apex call.
handleSave(event) {
const recordInputs = event.detail.draftValues.slice().map(draft => {
const fields = Object.assign({}, draft);
return { fields };
});
But in my application I know that I need to imperatively call my Apex class to handle this update, and I can do that. I am currently only passing back the JSONified values of the “draftValues” and the entire list itself, just to see how that works:
handleSave(event) {
var draftValuesStr = JSON.stringify(event.detail.draftValues);
var wrapList = JSON.stringify(this.pricesList);
updatePriceRecords({updateObjStr: draftValuesStr, wrapList: wrapList});
}
And this does bring back the “draft” values perfectly for me, as you can see below:
[{"priceUsd":"456.00","priceEur":"765.67","Id":"row-3"}]
And my Apex could handle the price updates if ONLY it had some unique ID (like the product number, in my case), so that is what I am asking how to do. All the string contains as an ‘ID’ is the row ID, which is not very helpful. I know that I can bring back the ENTIRE list, and then be able to associate the row ID with the appropriate record in the list and get the product number that way, but that is clearly a horribly inefficient idea, and there has got to be a better way.
I also considered somehow persisting my list into a CACHE (like a user setting?) so I could retrieve the original list that way, but that does not sound like a good idea either.
Also, I am thinking that I could somehow iterate through the JSONified draft values and insert the product ID appropriately into that list, but I am not sure how I would go about grabbing the product ID out of selected draft record.
If anybody could help me out with this I would really appreciate it. It seems to me that this would be a very common use case out there.
Thanks very much.
You need to add one more variable in your wrapper class like below:
public Boolean isSelected{get;set;}
Now map the checkboxes with this property so that you can get to know which record is selected. You can pass the complete wrapper list in your apex class and based on this isSelected property you can figure out which product is selecetd. In this way you will also get the unique code.
Let me know if you need any further help on this.
Thanks,
Abhishek Bansal.
Gmail: abhibansal2790@gmail.com
Skype: abhishek.bansal2790
Phone: +917357512102
You can contact me for any help on my gmail or skype.
If user are not going to select them manually then what is the use of showing them in page? Just want to understand what you are doing with these checkboxes.
If you are not using checkboxes than you can follow the below process:
- Instead of having a boolean variable, create one String variable like -> public String productId {get;set;}
- Store id of the respective product which should be unique across the rows.
- Now in your list that you are sending to your apex controller, send this Id also.
- Based on this Id you can update your records.
Kent, may be I am not able to answer you beacuse I have not seen your page. Its better we can connect on a call and resolve all of them at once. Let me know your thoughts on this.Thanks,
Abhishek Bansal.