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
requiredorpattern. - Returns
trueif the field passes validation,falseotherwise.
//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
checkValidityandsetCustomValidity.
// 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-input,lightning-combobox, andlightning-textarea) and validation logic. - The child component also has a button to self validate the fields.
The parent component can:
- Validate specific fields in the child component.
- Validate all fields in the child component.
Key Features and Highlights
- 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.
- 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.
- 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.
- 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