I have a LWC which outputs a list of Line Items. Here is createInvoiceLineItems.html:
<template>
<lightning-card title="Invoice Line Items">
<template for:each={lineItems} for:item="item" for:index="index">
<div key={item.key} class="slds-grid slds-wrap">
<div class="slds-col">
<lightning-input type="number" label="Quantity" value={item.quantity} onchange={handleQuantityChange} data-index={index}></lightning-input>
</div>
<div class="slds-col">
<lightning-input type="text" label="Description" value={item.description} onchange={handleDescriptionChange} data-index={index}></lightning-input>
</div>
<div class="slds-col">
<lightning-input type="number" formatter="currency" label="Amount" value={item.amount} onchange={handleAmountChange} data-index={index}></lightning-input>
</div>
</div>
</template>
<div class="slds-m-top_medium">
<lightning-button variant="success" label="Add Line Item" title="Add Line Item" onclick={addLineItem}></lightning-button>
<lightning-button variant="brand" label="Proceed" title="Proceed" onclick={handleProceed}></lightning-button>
</div>
</lightning-card>
</template>
Here is createInvoiceLineItems.js:
import { LightningElement, api, track } from 'lwc';
import { FlowAttributeChangeEvent, FlowNavigationNextEvent } from 'lightning/flowSupport';
export default class CreateInvoiceLineItems extends LightningElement {
@api availableActions = [];
@track _lineItems = [];
@api
get lineItems() {
return this._lineItems;
}
set lineItems(value) {
this._lineItems = value;
}
addLineItem() {
const newIndex = this._lineItems.length;
const newItem = { key: newIndex, quantity: '', description: '', amount: '' };
this._lineItems = [...this._lineItems, newItem];
}
handleQuantityChange(event) {
const index = event.target.dataset.index;
this._lineItems[index].quantity = event.target.value;
}
handleDescriptionChange(event) {
const index = event.target.dataset.index;
this._lineItems[index].description = event.target.value;
}
handleAmountChange(event) {
const index = event.target.dataset.index;
this._lineItems[index].amount = event.target.value;
}
handleProceed() {
const lineItems = this._lineItems.map((item) => {
return { key: item.key, quantity: item.quantity, description: item.description, amount: item.amount };
});
const jsonData = JSON.stringify({ lineItems });
// check if NEXT is allowed on this screen
if (this.availableActions.find((action) => action === 'NEXT')) {
// navigate to the next screen
const attributeChangeEvent = new FlowAttributeChangeEvent('lineItems', jsonData);
this.dispatchEvent(attributeChangeEvent);
const navigateNextEvent = new FlowNavigationNextEvent();
this.dispatchEvent(navigateNextEvent);
}
}
}
Here is createInvoiceLineItems.js-meta.xml:
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
<apiVersion>57.0</apiVersion>
<isExposed>true</isExposed>
<masterLabel>Create invoice line items</masterLabel>
<targets>
<target>lightning__FlowScreen</target>
</targets>
<targetConfigs>
<targetConfig targets="lightning__FlowScreen">
<property name="lineItems" type="String[]" label="Line Items"/>
</targetConfig>
</targetConfigs>
</LightningComponentBundle>
When using this component in my flow I can see that it outputs the following:
[{"lineItems":[{"key":0,"quantity":"1","description":"desc 1","amount":"1"},{"key":1,"quantity":"2","description":"desc 2","amount":"2"}]}]
I created an Apex class to parse this to Line Items. Here is LineItemJSONParser:
public class LineItemJSONParser {
@InvocableMethod(label='Parse Line Items' description='Converts JSON object into LineItem objects')
public static List<LineItem> parseLineItems(List<String> jsonInputList) {
List<LineItem> lineItems = new List<LineItem>();
for (String jsonInput : jsonInputList) {
Map<String, Object> jsonMap = (Map<String, Object>) JSON.deserializeUntyped(jsonInput);
List<Object> items = (List<Object>) jsonMap.get('lineItems');
for (Object item : items) {
Map<String, Object> itemMap = (Map<String, Object>) item;
LineItem lineItem = new LineItem();
lineItem.key = (Integer) itemMap.get('key');
lineItem.quantity = (String) itemMap.get('quantity');
lineItem.description = (String) itemMap.get('description');
lineItem.amount = (String) itemMap.get('amount');
lineItems.add(lineItem);
}
}
return lineItems;
}
public class LineItem {
@InvocableVariable(label='Key' description='Line Item key')
public Integer key;
@InvocableVariable(label='Quantity' description='Line Item quantity')
public String quantity;
@InvocableVariable(label='Description' description='Line Item description')
public String description;
@InvocableVariable(label='Amount' description='Line Item amount')
public String amount;
}
}
When using this in my flow, I do not get the option to select the output of createInvoiceLineItems
as an input for the parser. createInvoiceLineItems
appears to me to output an array of strings so I don't under stand why LineItemJSONParser.cls
cannot accept it in the flow.
EDIT: I have updated my parser so that it looks like the below:
public class LineItemJSONParser {
@InvocableMethod(label='Parse Line Items' description='Converts JSON input into LineItem objects')
public static List<List<LineItem>> parseLineItems(List<List<String>> jsonInputList) {
List<List<LineItem>> lineItemsList = new List<List<LineItem>>();
for (List<String> jsonInput : jsonInputList) {
List<LineItem> lineItems = new List<LineItem>();
for (String jsonString : jsonInput) {
LineItem lineItem = (LineItem) JSON.deserialize(jsonString, LineItem.class);
lineItems.add(lineItem);
}
lineItemsList.add(lineItems);
}
return lineItemsList;
}
public class LineItem {
@InvocableVariable(label='Key' description='Line Item key' required=true)
public Integer key;
@InvocableVariable(label='Quantity' description='Line Item quantity' required=true)
public String quantity;
@InvocableVariable(label='Description' description='Line Item description' required=true)
public String description;
@InvocableVariable(label='Amount' description='Line Item amount' required=true)
public String amount;
}
}
According to the flow, the output is as below:
[LineItem : { "quantity" : "1", "key" : 0, "description" : "1", "amount" : "1" },LineItem : { "quantity" : "2", "key" : 1, "description" : "2", "amount" : "2" }]
However I am unable to access this output in my flow.
List<List<LineItem>>
), so you'll need to adjust your code to handle this return type.[LineItem : { "quantity" : "1", "key" : 0, "description" : "1", "amount" : "1" },LineItem : { "quantity" : "2", "key" : 1, "description" : "2", "amount" : "2" }]
. Output type of my parser isList<List<LineItem>>
@sfdcfox