7

Let's say I have a Lightning-Web-Component that uses lightning-record-form like this:

 <lightning-record-form
    record-id={recordId}
    object-api-name="Opportunity"
    fields={myFields}
    columns="2"
    onerror={handleError}
    mode="view"}>
    </lightning-record-form>

and a corresponding javascript file with the following functions defined:

 handleError(event) {
        console.log("handleError event");
        console.log(JSON.stringify(event.detail));
    }

 showToast(theTitle, theMessage, theVariant) {
        const event = new ShowToastEvent({
            title: theTitle,
            message: theMessage,
            variant: theVariant
        });
        this.dispatchEvent(event);
    }

How do I prevent this from displaying the default error message?

enter image description here

I have tried using event.preventDefault(); and event.stopImmediatePropagation(); like this:

handleError(event) {
    event.preventDefault();
    event.stopImmediatePropagation();
    this.showToast("Error", event.detail.detail, "error");
}

Does anyone have any ideas about how to properly handle an error using lightning-record-form? I don't want my users getting a big ugly error message that they cannot dismiss.

1
  • 1
    Remember to accept the post that best helped answer your question =)
    – glls
    Commented Mar 30, 2019 at 1:21

4 Answers 4

6

Okay, so thanks to @sfdcFox I realized that the error handling override in the lightning-record-form is not able to be canceled, so I just used a combination of lightning-record-edit-form and lightning-record-view-form and I just omitted the lightning-messages tag. I used a js variable called "editMode" to conditionally render lightning-input-field vs lightning-output-field. Then, I still use handleError() to parse the error message and display a closable error toast to the user.

<template>
<lightning-record-edit-form record-id={recordId} object-api-name="Opportunity" onerror={handleError}>
    <lightning-record-view-form record-id={recordId} object-api-name="Opportunity">
        <div class="slds-box">
            <lightning-card title="Opportunity Overview">
                <template if:true={editMode}>
                    <lightning-button variant="Neutral" label="Save" title="Save" type="submit"
                        icon-name="utility:save" slot="actions" class="slds-p-around_xxx-small"></lightning-button>
                    <lightning-button variant="brand" label="Cancel" title="Cancel" type="reset"
                        onclick={clearEditMode} icon-name="utility:undo" slot="actions"
                        class="slds-p-around_xxx-small"></lightning-button>
                </template>
                <template if:false={editMode}>
                    <lightning-button variant="brand" label="Edit" title="Edit" onclick={setEditMode}
                        icon-name="utility:edit" slot="actions" class="slds-p-around_xxx-small"></lightning-button>
                </template>
                <lightning-layout multiple-rows="true">
                        <lightning-layout-item size="6" padding="around-small">
                            <template if:true={editMode}>
                                <lightning-input-field field-name="name"></lightning-input-field>
                            </template>
                            <template if:false={editMode}>
                                    <lightning-output-field field-name="name"></lightning-output-field>
                                </template>
                        </lightning-layout-item>
                       <!-- ... repeat above for all fields... -->
                </lightning-layout>
            </lightning-card>
        </div>
    </lightning-record-view-form>
</lightning-record-edit-form>

Here is js controller:

@track editMode;

    connectedCallback() {
        this.editMode = false;
    }

    setEditMode(){
        this.editMode = true;
    }

    clearEditMode(){
        this.editMode = false;
    }

    handleError(event) {
        let message = event.detail.detail;
        //do some stuff with message to make it more readable
        message = "Something went wrong!";
        this.showToast(TOAST_TITLE_ERROR, message, TOAST_VARIANT_ERROR);
       this.clearEditMode();
    }
    showToast(theTitle, theMessage, theVariant) {
        const event = new ShowToastEvent({
            title: theTitle,
            message: theMessage,
            variant: theVariant
        });
     this.dispatchEvent(event);
    }
2

Do not use exceptions in your triggers. You should always use addError on the record or a specific field. Your users will have a much more user-friendly experience if you use the appropriate API.

7
  • 1
    while that is true, that does not answer the question I am trying to solve. In case of an error, how do I use the "onerror" attribute of the lightning-web-component to prevent default behavior. why does eventpreventDefault() or event.stopPropogation not work is what I am asking. Commented Mar 26, 2019 at 16:08
  • 1
    @MitchSpano The lightning-record-edit-form is designed to behave just like the UI. If you don't want to do that, you're going to need to write your own component. The documentation makes no mention of being able to cancel the default error handling, you can only do additional things in response to an error.
    – sfdcfox
    Commented Mar 26, 2019 at 16:14
  • 1
    fox, the documentation says:"The component has a default submit handler. To override the submit handler, use the onsubmit attribute. Errors are automatically handled and displayed. To customize them, use the onerror attribute" developer.salesforce.com/docs/component-library/documentation/… Commented Mar 26, 2019 at 16:15
  • so it is possible, and even so, the larger question remains, why are lightning component events not treated like standard javascript events? calling event.PreventDefault should cancel the event as per w3c: w3schools.com/jsref/event_preventdefault.asp Commented Mar 26, 2019 at 16:18
  • 1
    @MitchSpano preventDefault is only for cancelable events, not all events can be canceled. For example, even in W3C standards, you can't cancel the window unload event. stopPropagation is used for events that bubble; the onerror event does not propagate. Events do behave very much like JavaScript events, but event handling is a lot more complicated than you give it credit for. If you're interested in more than a comment-long answer, you might want to ask the question "why are LC events not like standard JS events?" It's a decently complicated topic that I can't do justice for in a comment.
    – sfdcfox
    Commented Mar 26, 2019 at 16:36
0

You can pass your record edit form error message in reduce errors method.

handleError(event) {
    let errors = this.reduceErrors(error); // you can pass your 
                                             recordedit form error here
    let errorMsg = errors.join('; ');
    this.showToast('Error!', errorMsg, 'error');
   this.clearEditMode();
}

showToast(title, message, variant) {
    const event = new ShowToastEvent({
        title: title,
        message: message,
        variant: variant
    });
 this.dispatchEvent(event);
}



    reduceErrors(errors) {

    if (!Array.isArray(errors)) {
        errors = [errors];
    }
    return (
        errors
            // Remove null/undefined items
            .filter((error) => !!error)
            // Extract an error message
            .map((error) => {
                // UI API read errors
                if (Array.isArray(error.body)) {
                    return error.body.map((e) => e.message);
                }
                // Page level errors
                else if (
                    error?.body?.pageErrors &&
                    error.body.pageErrors.length > 0
                ) {
                    return error.body.pageErrors.map((e) => e.message);
                }
                // Field level errors
                else if (
                    error?.body?.fieldErrors &&
                    Object.keys(error.body.fieldErrors).length > 0
                ) {
                    const fieldErrors = [];
                    Object.values(error.body.fieldErrors).forEach(
                        (errorArray) => {
                            fieldErrors.push(
                                ...errorArray.map((e) => e.message)
                            );
                        }
                    );
                    return fieldErrors;
                }
                // UI API DML page level errors
                else if (
                    error?.body?.output?.errors &&
                    error.body.output.errors.length > 0
                ) {
                    return error.body.output.errors.map((e) => e.message);
                }
                // UI API DML field level errors
                else if (
                    error?.body?.output?.fieldErrors &&
                    Object.keys(error.body.output.fieldErrors).length > 0
                ) {
                    const fieldErrors = [];
                    Object.values(error.body.output.fieldErrors).forEach(
                        (errorArray) => {
                            fieldErrors.push(
                                ...errorArray.map((e) => e.message)
                            );
                        }
                    );
                    return fieldErrors;
                }
                // UI API DML, Apex and network errors
                else if (error.body && typeof error.body.message === 'string') {
                    return error.body.message;
                }
                // JS errors
                else if (typeof error.message === 'string') {
                    return error.message;
                }
                // Unknown error shape so try HTTP status text
                return error.statusText;
            })
            // Flatten
            .reduce((prev, curr) => prev.concat(curr), [])
            // Remove empty strings
            .filter((message) => !!message)
    );
}
0

I have tried it and it worked.

Place lightning message tag inside your html component. Add data-id attribute.

<lightning-messages data-id='formerror'> </lightning-messages>

Then inside your handleError method add this:

handleError(event){
    this.template.querySelector('[data-id="formerror"]').setError('your custom error message');
}

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .