How to Do Client Side JS Custom Validations in Salesforce Lightning Web Components (LWC)

How to Do Client Side JS Custom Validations in Salesforce Lightning Web Components (LWC)

Introduction

Validation is essential to ensure data correctness and user-friendly error handling. In Lightning Web Components (LWC), the core methods used for field validation are setCustomValidity, checkValidity, and reportValidity. This blog explains these concepts before diving into a practical Parent-Child LWC example.

Understanding Validation Methods

1. setCustomValidity
  • Allows you to set a custom error message for a field.
  • If the input does not meet certain criteria, this method specifies the error message to display.
  • To reset the error, pass an empty string ('').

Example:

//Set error message for UI
input.setCustomValidity('This field cannot be empty.');
// Clear the error message for UI
input.setCustomValidity('');
2. checkValidity
  • Validates the field against its constraints, such as required or pattern.
  • Returns true if the field passes validation, false otherwise.
//check if the input field is valid
if (input.checkValidity()) {
    console.log('Field is valid!');
} else {
    console.log('Field is invalid!');
}
3. reportValidity
  • Displays the validation error to the user if the field is invalid.
  • Combines the behavior of checkValidity and setCustomValidity.
// Report validity to show the error message
input.reportValidity();

Example Scenario: Parent-Child Validation

In this example, we’ll create a Parent-Child LWC setup where the Parent Component triggers validations in the Child Component.

  • The parent component contains buttons that trigger validation methods in the child component.
  • The child component has form fields (like lightning-inputlightning-combobox, and lightning-textarea) and validation logic.
  • The child component also has a button to self validate the fields.

The parent component can:

  1. Validate specific fields in the child component.
  2. Validate all fields in the child component.
Key Features and Highlights
  1. Parent-Triggered Validation:
    • The parent component (parentValidation) interacts with the child (childValidation) using template.querySelector(‘c-child-validation’) to invoke validation methods.
    • For example, clicking the parent’s button calls either validateSpecificFields([‘nameField’, ‘picklistField’]) or validateFields() on the child.
  2. Field-Specific Validation:
    • The child component exposes a method validateSpecificFields(fieldNames) that validates only the specified fields (like Name and Picklist).
    • It uses the field’s data-id to find the element and applies custom error messages if validation fails.
  3. Comprehensive Validation:
    • The child’s validateFields() method validates all fields, including the textarea. It checks if the textarea is empty and if all required inputs are filled, setting error messages as needed.
  4. Dynamic Error Messages:
    • The child uses setCustomValidity to display user-friendly error messages directly on the form fields.
    • For example, if the textarea is empty, it shows “Please fill all required fields..”, and for short comments, “Comments must be at least 5 characters long.”
Sample Code –

In the below code we have also shown below –

  • How you can set custom validity on onchange and remove it on onblur.
  • How you can get the element using html input field type selector e.g. this.template.querySelectorAll(‘lightning-input, lightning-combobox’) or you can get the html input field via a custom attribute like data-id, e.g. this.template.querySelector(‘[data-id=”textareaField”]’);
<!–childValidation.html–>
<template>
<div>
<div id="test" data-id="test1"></div>
<lightning-card title="Child Validation Example">
<div class="slds-m-around_medium">
<lightning-input
label="Name"
data-id="nameField"
class="textareaclass"
onchange={handleInputChange}
onblur={clearFieldValidity} required>
</lightning-input>
<lightning-combobox
label="Picklist"
data-id="picklistField"
placeholder="Select an option"
options={picklistOptions}
onchange={handleInputChange}
onblur={clearFieldValidity} required>
</lightning-combobox>
<lightning-textarea
label="Comments"
data-id="textareaField"
onchange={handleTextareaChange}
onblur={clearFieldValidity}>
</lightning-textarea>
</div>
<lightning-button label="Validate All Fields (Child Cmp Button)" onclick={handleSubmit}></lightning-button>
</lightning-card>
</div>
</template>
/*childValidation.js*/
// Import necessary LWC modules and decorators
import { LightningElement, track, api } from 'lwc';
/**
* Parent vaidation component that interacts with a child component for field validation.
* This component provides methods to validate specific fields or all fields in the child component.
*/
/**
* ChildValidation component that provides methods to validate specific fields or all fields.
* This component contains form fields such as name, picklist, and textarea.
* It allows the parent component to validate specific fields or all fields as needed.
*/
export default class ChildValidation extends LightningElement {
// Track the form data for the fields in the child component
@track formData = {
nameField: '',
picklistField: '',
textareaField: ''
};
// Define the options for the picklist field
picklistOptions = [
{ label: 'Option 1', value: 'option1' },
{ label: 'Option 2', value: 'option2' },
{ label: 'Option 3', value: 'option3' }
];
/**
* handleInputChange method is used to handle input changes in the form fields.
* It updates the formData object with the new value of the input field.
* This method is typically called when the user interacts with the form fields.
* @param {Event} event – The input change event containing the new value.
* @return {void}
*/
handleInputChange(event) {
const fieldName = event.target.name;
this.formData[fieldName] = event.target.value;
}
/**
* clearFieldValidity method is used to clear the custom validity of a field.
* It is typically called when the user interacts with the field to remove any previous validation messages.
* @param {Event} event – The input event containing the field that needs to be cleared.
* @return {void}
*/
clearFieldValidity(event) {
// clear any custom validity so checkValidity() can pass when appropriate
event.target.setCustomValidity('');
event.target.reportValidity();
}
/**
* handleTextareaChange method is used to handle changes in the textarea field.
* It updates the formData object with the new value of the textarea field and enforces a minimum character length.
* This method is typically called when the user types or leaves the textarea field.
* @param {Event} event – The change event containing the new value of the textarea.
* @return {void}
*/
handleTextareaChange(event) {
// Get the textarea element and its value
const textarea = event.target;
// Use the value property to get the current value of the textarea
const value = textarea.value || '';
// Update the formData object with the new value
this.formData.textareaField = value;
// Clear any previous custom validity messages
textarea.setCustomValidity('');
// Check if the value is empty or less than 5 characters
if (value.length > 0 && value.length < 5) {
// If the value is less than 5 characters, set a custom validity message
textarea.setCustomValidity('Comments must be at least 5 characters long.');
}
// Report validity to show the error message if any
textarea.reportValidity();
}
/**
* validateSpecificFields method is used to validate specific fields in the child component.
* It checks the validity of the 'nameField' and 'picklistField' in the child component.
* This method is typically called when the parent component needs to ensure that certain fields are filled out correctly before proceeding with further actions.
* @param {Array} fieldNames – An array of field names to validate.
* @return {boolean} – Returns true if all specified fields are valid, false otherwise.
*/
@api validateSpecificFields(fieldNames) {
// Define a variable to track the validity of fields
let isValid = true;
// Validate the name field
fieldNames.forEach(fieldName => {
// Get the input element for the specified field instance using data-id attribute, by querying the DOM using the template.querySelector method for validation
const input = this.template.querySelector(`[data-id="${fieldName}"]`);
// Check if the input exists and is required
if (input && !input.checkValidity()) {
switch (fieldName) {
case 'nameField':
// Set custom validity message for name field if it is invalid
input.setCustomValidity('Please enter a value for name.');
break;
case 'picklistField':
// Set custom validity message for picklist field if it is invalid
input.setCustomValidity('Please select a valid option from the picklist.');
break;
default:
// Set a generic custom validity message for any other field
input.setCustomValidity('This field is required.');
}
// Report validity to show the error message
input.reportValidity();
// Set isValid to false if any input is invalid
isValid = false;
} else {
// If the input is valid, clear any custom validity message
input.setCustomValidity('');
}
});
// return the validity status
return isValid;
}
/**
* validateFields method is used to validate all fields in the child component.
* It checks the validity of all fields, including text areas and input fields.
* This method is typically called when the parent component needs to ensure that all fields are filled out correctly before proceeding with further actions.
* @return {boolean} – Returns true if all fields are valid, false otherwise.
*/
@api validateFields() {
//Define a variable to track the validity of all fields
let isValid = true;
// Get the text area element instance using data-id attribute, by querying the DOM using the template.querySelector method for validation
const textArea = this.template.querySelector('[data-id="textareaField"]');
//check if the text area component exist and it is not empty
if (textArea && !textArea.value) {
//If the text area is empty or less than 5 characters, set custom validity message
textArea.setCustomValidity('Please fill all required fields.');
// Report validity to show the error message
textArea.reportValidity();
isValid = false;
} else {
// If the text area is valid, clear any custom validity message
textArea.setCustomValidity('');
}
/**
* Get all input elements (lightning-input and lightning-combobox) instance in the component,
* by querying the DOM using the template.querySelectorAll method for validation.
*/
const inputs = this.template.querySelectorAll('lightning-input, lightning-combobox');
// Iterate through each input element to check its validity
inputs.forEach(input => {
// Check if the input exists and is required
if (!input.checkValidity()) {
// Set custom validity message if the field is invalid
input.setCustomValidity('Please fill all required fields.');
// Report validity to show the error message
input.reportValidity();
// Set isValid to false if any input is invalid
isValid = false;
}
});
// Return the overall validity status
return isValid;
}
handleSubmit(event) {
// Prevent the default form submission behavior
event.preventDefault();
// Validate all fields before proceeding
if (this.validateFields()) {
console.log('All fields are valid. Form submitted successfully!');
// You can add further logic here to handle successful form submission
} else {
console.log('There are validation errors in the form. Please correct them before submitting.');
}
}
}
<!–parentValidation.html–>
<template>
<div>
<lightning-card title="Parent Validation Example">
<div class="slds-m-around_medium">
<c-child-validation ref="childComponent"></c-child-validation>
<lightning-button label="Validate Name and Picklist Of Child Cmp (Parent Cmp Button)" onclick={validateSpecificFields}></lightning-button>
<lightning-button label="Validate All Fields Child Cmp (Parent Cmp Button)" onclick={validateAllFields}></lightning-button>
</div>
</lightning-card>
</div>
</template>
/*parentValidation.js*/
// Import necessary LWC modules and decorators
import { LightningElement} from 'lwc';
/**
* Parent vaidation component that interacts with a child component for field validation.
* This component provides methods to validate specific fields or all fields in the child component.
*/
export default class ParentValidation extends LightningElement {
/**
* validateSpecificFields method is used to validate specific fields in the child component.
* It checks the validity of the 'nameField' and 'picklistField' in the child component.
* This method is typically called when the parent component needs to ensure that certain fields are filled out correctly before proceeding with further actions.
* @return {void}
*/
validateSpecificFields() {
//get the child component instance by querying the DOM using the template.querySelector method.
const childComponent = this.template.querySelector('c-child-validation');
//check if the child component exists before calling its method.
if (childComponent) {
// Call the validateSpecificFields method on the child component, passing an array of field names to validate.
const isValid = childComponent.validateSpecificFields(['nameField', 'picklistField']);
if (isValid) {
console.log('Name and Picklist fields are valid!');
} else {
console.log('Validation failed for Name or Picklist field.');
}
}
}
/**
* validateAllFields method is used to validate all fields in the child component.
* It checks the validity of all fields in the child component, including text areas and input fields.
* This method is typically called when the parent component needs to ensure that all fields are filled out correctly before proceeding with further actions.
* @return {void}
*/
validateAllFields() {
// Get the child component instance by querying the DOM using the template.querySelector method.
const childComponent = this.template.querySelector('c-child-validation');
// Check if the child component exists before calling its method.
if (childComponent) {
// Call the validateFields method on the child component to validate all fields.
const isValid = childComponent.validateFields();
if (isValid) {
console.log('All fields in the child component are valid!');
} else {
console.log('There are validation errors in the child component.');
}
}
}
}

Conclusion

Understanding and implementing validation methods like setCustomValidity, checkValidity, and reportValidity ensures that your LWC applications handle user input gracefully. By combining these methods in Parent-Child components, you can build robust forms with user-friendly validation mechanisms.

Leave a comment