1

I'm new to LWCs development. I'm having an issue understanding the order of execution for the lightning-record-edit-form component when a Parent lwc has multiple Child lwcs. Each Child component contains a lightning-record-edit-form component as well so the save when submit is nested. When submitting the form and a validation errors, in some of the Child components (not all) the error is not propagated back to the Parent before the Parent components onsuccess event fires, so to the user it looks like both and error occurs and the transaction was successful.

The lightning-record-edit-form developer documentation says that when submitting the form events fire in this order: onclick, submit, then success or error. I'm clearyly missing something but don't know what it is. Although I have multiple components, the structure of each is the same, but each focuses on a specific section of my requirement.Any suggestions would be helpful. Thanks in advance.

Below is a mockup of my code structure. I only included one component because the structure of each is the same just different input fields:

ParentComponent.html

    <div class="slds-media slds-media_center slds-grid slds-wrap slds-media_small slds-box">
        <lightning-card title="Parent Component" icon-name="custom:custom13" style="width: 100%">
            <lightning-layout-item padding="around-medium">                                    
                <div class="slds-media__body">                        
                    <lightning-record-edit-form record-id={recordId} 
                                                object-api-name={objectApiName} 
                                                onload={handleOnLoad}                                                    onsubmit={handleSubmit}                                                                  
                                                onerror={handleFormError}                                                    
                                                onsuccess={handleSuccess}
                                                density="auto">
                        <div class="slds-grid slds-gutters slds-wrap">
                            <!-- lightning-input-fields here -->                                                                    
                        </div>                                                     
                        <div class="slds-docked-form-footer stickyFooter bottomfooter slds-large-size">                               
                            <lightning-button class="slds-var-m-around_xx-small" label="Cancel" onclick={handleReset}></lightning-button>
                            <lightning-button class="slds-var-m-around_xx-small" label="Save" name="save" type="submit" onclick={submitClick} variant="brand"></lightning-button>                                
                        </div>                                     
                    </lightning-record-edit-form>                    
                </div>
            </lightning-layout-item>            
        </lightning-card>                  
    </div>    
    <div class="slds-media__body">      
        <!--
            Only load these components after the Parent is done loading and retrieving the child component ids
        -->   
        <template if:true={finishedloading}>    
            <!--Conditional rendering of Subtasks-->
            <template if:true={displayComponentA}>
                <div class="slds-card">
                <c-pc-component-a record-id={componentARecordId} 
                        onload={handleOnLoad}
                        onsubmit={handleSubmit}
                        onerror={handleError} 
                        onupdatecomponentaprogress={handleUpdateProgress}></c-pc-component-a>
                </div>
            </template>

            <template if:true={displayComponentB}>
                <div class="slds-card">
                    <c-pc-component-b record-id={componentBRecordId} 
                        onload={handleOnLoad}
                        onsubmit={handleSubmit}
                        onerror={handleError} 
                        onupdatecomponentbprogress={handleUpdateProgress}></c-pc-component-b>
                </div>
            </template>

            ........

            <template if:true={displayComponentN}>
                <div class="slds-card">
                    <c-pc-component-n record-id={componentNRecordId} 
                        onload={handleOnLoad}
                        onsubmit={handleSubmit}
                        onerror={handleError}
                        onupdatecomponentnprogress={handleUpdateProgress}></c-pc-component-n>
                </div>                
            </template>                
        </template>
    </div>    

ParentComponent.js

handleOnLoad(event){
    ...
    
    //Set the flag for which Child Component to display        
    this.showSubtasks();
    
    this.finishedloading = true;          
    ....
}

handleSuccess(event) {
           
    //Only show toast if no error from Child component(s)  
    if(((this.error == undefined) || (this.error == null))) {                   

        const toastEvent = new ShowToastEvent({
            title: "Platform Change Saved",
            message: "The record was successfully saved.",
            variant: "success"

        });
        this.dispatchEvent(toastEvent);            
    }               
    
}

handleSubmit(event) {
    
    //Stop the form from submitting
    event.stopPropagation();

    //This is also required to suppress the default submit process
    event.preventDefault();
    
    ...
    
    if(((this.error == undefined) || (this.error == null))) {
        console.log('NO ERRORS OCCURRED calling submit on form - this.error = ' + this.error);
        this.template.querySelector('lightning-record-edit-form').submit();           
            
    }             
    
}

async submitClick() {
    
    if(this.displayComponentA == true) {            
    
        await this.template.querySelector('c-pc-component-a').submitClick(); 
        
    }

    if(this.displayComponentB == true) {            
    
        await this.template.querySelector('c-pc-component-b').submitClick(); 
        
    }
    
    ... 
    
    if(this.displayComponentN == true) {            
    
        await this.template.querySelector('c-pc-component-n').submitClick(); 
        
    }

}

// handle errors when submit button press
handleFormError(event){
    this.error = event.detail;
    console.error("platformChange.handleFormError.error = " + this.error);
}

// handle errors from self
handleError(error){
    this.error = error;
}
    
// handle error from child (subtask) components
/* This removes the component from the document, so can't use this...
errorCallback(error, stack){
    this.error = error;
    console.error("platformChange.errorCallback.error = " + this.error);
}
*/

ChildComponent.html

ChildComponent.js

//declarators..

handleOnLoad(event) {
    var record = event.detail.records;

    this.setReadOnlyFlag();
    this.updateProgress();

}        

handleSuccess(event) {    

    this.isValidated = true;
    this.error = undefined;                

}


handleSubmit(event) {
    //Tried this but don't think it's needed in the Child
    //Stop the form from submitting
    //event.stopPropagation();

    //suppress the default submit process
    //event.preventDefault();

    this.error = undefined;              
}

@api async submitClick(){
        
    this.error = undefined;

    //Timeline Status of the Parent
    if(this.timelineStatus == 'Complete') {

        //Stage of the Child
        if(this.subtaskStage == 'N/A' || this.subtaskStage == 'Live') {   
            
            try{
                await this.template.querySelector('lightning-record-edit-form').submit();                                                                    
                this.isValidated = true;
                this.error = undefined;
                              
            }
            catch (err) {
                this.error = err;
                this.isValidated = false;                           
            
                //send the error back to the ParentComponent
                const selectedEvent = new CustomEvent('error', {detail: this.error});
                this.dispatchEvent(selectedEvent);                      
                
            }
        }
        else {
            this.isValidated = false;                  
            this.error = "The Stage Must be N/A or Live when Timeline Status = Complete. \nPlease update and try again!";            
            
            //send the error back to the ParentComponent
            const selectedEvent = new CustomEvent('error', {detail: this.error});
            this.dispatchEvent(selectedEvent);                 
        }
        
    }
    else {                        
        
        try {
            await this.template.querySelector('lightning-record-edit-form').submit();
                                 
            this.isValidated = true;
            this.error = undefined;                
        }
        catch (err) {
            this.isValidated = false;
            this.error = err;
            
            //send the error back to the ParentComponent
            const selectedEvent = new CustomEvent('error', {detail: this.error});
            this.dispatchEvent(selectedEvent);                
        }
    } 
    
}

handleError(event){
    
    //An error occurred
    this.isValidated = false;       
   
    
    // Error Handling
    
    if (event.detail.output.errors != null) {            
        // Loop & Display Errors
        for (let index = 0; index < event.detail.output.errors.length; index++) {
            console.log('Displaying Errors');
            event.detail.output.errors[index].message + '\n';                
            this.error += event.detail.output.errors[index].errorCode + '- ' + event.detail.output.errors[index].fieldLabel + ' ' + event.detail.output.errors[index].message + '\n';                
        }
       
        console.log(JSON.stringify(this.error));
        const selectedEvent = new CustomEvent('error', {detail: this.error});
        this.dispatchEvent(selectedEvent);  

    }
    if (event.detail.output.fieldErrors != null) {
        console.log('Displaying Field Errors');

        let fieldErrors = event.detail.output.fieldErrors;
        let val = Object.values(fieldErrors);
        this.error = Object.keys(fieldErrors) + ' ' + val[0][0]["message"];
        console.log('pcSSO.handleError-FIELD ERRORS - ' + this.error);

        //Send error back to ParentComponent...
        const selectedEvent = new CustomEvent('error', {detail: this.error});
        this.dispatchEvent(selectedEvent);                       

    } else {
        console.log('Displaying Generic Errors')

        this.error = event.message;
        
        console.log(JSON.stringify(this.error));
        const selectedEvent = new CustomEvent('error', {detail: this.error});
        this.dispatchEvent(selectedEvent);  
    }       
    
}
0
0

Thank you those who have viewed my post in an attempt to help. I figured out the issue. I had to refactor my code because I had context issues. All a part of the learning process I guess, but I'm good now until the next issue! :)

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.