Lightning Web Components – State Management/Data Binding with LWC with Many Related Records

I'm creating a form that displays a fair amount of information and needs to be update-able. I've looked into using lightning data service and <lighnting-record-edit/view> components but there is quite a bit of data coming from a handful of objects where these components just don't do the job.

I started putting sections of the form into their own components and ran into a problem with the one-way data binding when I went to start making it updateable. I spent a lot of time brainstorming the best way to get around this and I've come up with about 4 options.

Option 1

Don't componentize my form and host everything on 1 component. This allows me to avoid data binding issues and I can easily update the data without any events. However it comes with the trade off of having a large component

Option 2

Pass each form field as it's own @api property to getters/setters and when I need to save just call each components' proptery's getter for the modified value. Pros to this is that everything is a primitive data value which is the recommended way to pass values. However some sections have many fields to display and it will become overbearing.

<template>
    <c-child1 
        field1={myModel1.field1}
        field2={myModel1.field2}
        ...
        fieldN={myModel1.fieldN}>
    </c-child1>
    <c-child2 
        field1={myModel2.field1}
        field2={myModel2.field2}
        ...
        fieldN={myModel2.fieldN}>
    </c-child2>
    ... etc
</template>

Parent Component Controller:

save() {
    let records = {
        asset : {
            field1: this.template.querySelector('c-child1').field1,
            ...
        },
        ...
    }
    //call apex method to save records

}

Very simple example

Option 3

Clone the passed in object in the setter and assign it to a @track property in the component controller. When I save I can call the components getter to get the modified data like in the above example. This allows me to have an independent state from the passed in read only object. It just seems a bit hacky and defeats the purpose of read only properties as a feature

Component:

<c-asset-information 
    asset={model.asset}>
</c-asset-information>

Component Controller:

@track
state;

@api 
get asset() {
    return this.state.asset;
}

set asset(asset) {
    this.state = {
        asset: JSON.parse(JSON.stringify(asset))
    };
}

handleChange = (event) => {
    this.state.asset.Comments__c = event.target.value;
}

Option 4

Use the @api property to display the data and when it needs to be updated fire an event to the parent component and update the source object/properties. This seems like the most logical, but also seems like I need to write a ton of boiler plate code

Child Component:

<template if:false={editAsset}>
    {asset.Comments__c}
</template>
<template if:true={editAsset}>
    <lightning-textarea label="" value={asset.Comments__c} onchange={handleChange}></lightning-textarea>
</template>

handleChange = (event) => {
    this.dispatchEvent(new CustomEvent('commentsUpdated', {detail: event.target.value}))
}

Parent Component Handler:

oncommentsUpdateHandler(event) {
    this.asset.Comments__c = event.detail
}

State management is kind of confusing for me with lightning web components. What is the best way to show and update a lot of data from different records?

Best Answer

While It is logical to use Option #4, I actually had implemented sort of Option 3 for my use case:

I had a huge form with multiple pages working with custom metadata for conditional rendering and multiple objects and had a challenge to make the whole thing loosely coupled.

So I enclosed all the various sections of the form within a parent component, all the child components had their own copies of original records, upon save, parent component would call public method within each component which validated the sections as per their own requirements and returned an object with only those values that were updated. These properties were then updated into original copy and finally updated.

Above architecture helped me separate the concerns of validation, multiple records, concerns etc to make logic loosely coupled and conditional as needed, needless to say a lot of logic was similar for each component so I shared that logic for each section.

Related Topic