Wednesday 24 July 2024

Dynamic Data Collection and Nested Structure Creation in LWC with Apex

To handle various types of input elements dynamically, you can use a more generic approach to select all form elements and collect their values. You'll need to modify the JavaScript code to handle different types of inputs (e.g., radio buttons, checkboxes, dropdowns) accordingly.

LWC JavaScript Level

HTML Template:
html
Copy code
<template>

    <lightning-input label="Name" name="EditableFields.Name"></lightning-input>

    <lightning-input label="Age" name="EditableFields.Age" type="number"></lightning-input>

    <lightning-input label="Mom" name="EditableFields.Parents.Mom"></lightning-input>

    <lightning-input label="Dad" name="EditableFields.Parents.Dad"></lightning-input>

    <lightning-radio-group 

        label="Gender" 

        name="EditableFields.Gender"

        options={genderOptions}

        onchange={handleChange}>

    </lightning-radio-group>

    <lightning-combobox

        name="EditableFields.Country"

        label="Country"

        placeholder="Select Country"

        options={countryOptions}

        onchange={handleChange}>

    </lightning-combobox>

    <lightning-button label="Submit" onclick={handleSubmit}></lightning-button>

</template>


JavaScript Controller:
javascript
Copy code
import { LightningElement } from 'lwc';

import submitData from '@salesforce/apex/YourApexClass.submitData';


export default class EditableForm extends LightningElement {

    genderOptions = [

        { label: 'Male', value: 'Male' },

        { label: 'Female', value: 'Female' },

        { label: 'Other', value: 'Other' }

    ];


    countryOptions = [

        { label: 'USA', value: 'USA' },

        { label: 'Canada', value: 'Canada' },

        { label: 'India', value: 'India' }

    ];


    handleSubmit() {

        const fields = {};

        const inputs = this.template.querySelectorAll('lightning-input, lightning-radio-group, lightning-combobox');


        inputs.forEach(input => {

            if (input.type === 'checkbox') {

                fields[input.name] = input.checked;

            } else if (input.type === 'radio') {

                fields[input.name] = input.value;

            } else {

                fields[input.name] = input.value;

            }

        });


        submitData({ fields: JSON.stringify(fields) })

            .then(result => {

                console.log('Submitted Data: ', result);

            })

            .catch(error => {

                console.error('Error: ', error);

            });

    }

}


Apex Controller

Apex Controller:
apex
Copy code
public with sharing class YourApexClass {

    @AuraEnabled

    public static String submitData(String fields) {

        try {

            Map<String, Object> fieldsMap = (Map<String, Object>) JSON.deserializeUntyped(fields);


            Map<String, Object> customerData = new Map<String, Object>();

            customerData.put('CustomerId', 'D1');

            customerData.put('IdempotencyKey', '012ADQ');

            Map<String, Object> editableFields = new Map<String, Object>();

            customerData.put('EditableFields', editableFields);


            for (String path : fieldsMap.keySet()) {

                dynamicInsert(editableFields, path.split('\\.'), fieldsMap.get(path));

            }


            return JSON.serialize(customerData);

        } catch (Exception e) {

            throw new AuraHandledException('Error: ' + e.getMessage());

        }

    }


    private static void dynamicInsert(Map<String, Object> map, List<String> pathParts, Object value) {

        if (pathParts.size() == 1) {

            map.put(pathParts[0], value);

            return;

        }


        String key = pathParts[0];

        if (!map.containsKey(key)) {

            map.put(key, new Map<String, Object>());

        }


        dynamicInsert((Map<String, Object>) map.get(key), pathParts.subList(1, pathParts.size()), value);

    }

}


Explanation

  1. LWC JavaScript Level:

    • The handleSubmit method is triggered when the submit button is clicked.

    • It selects all lightning-input, lightning-radio-group, and lightning-combobox elements and iterates over them to build the fields object, where the key is the name attribute (which contains the bind path) and the value is the input's value.

    • For checkbox inputs, it stores the checked state; for radio buttons and other inputs, it stores the value.

    • The fields object is then serialized to JSON and sent to the Apex controller using the submitData method.

  2. Apex Controller:

    • The submitData method receives the JSON string and deserializes it into a Map<String, Object>.

    • customerData is initialized with fixed values for CustomerId and IdempotencyKey.

    • For each entry in the fieldsMap, the dynamicInsert method is called to construct the nested structure.

    • dynamicInsert is a recursive method that navigates through the path parts and dynamically creates nested maps as needed, inserting the value at the correct position.

This approach ensures that you can collect all input data with a single handler and dynamically create the required structure in Apex based on the received bind fields, regardless of the type of input element.

No comments:

Post a Comment