afv-library/skills/generating-lwc-components/assets/form-component/formComponent.js
sandipkumar-yadav 37aa84df42
feat: @W-22444026@ Introducing Core Skills, Datacloud Skills, Industries and Utility Skills. (#268)
* Migrating Core Salesforce Skills

* Updating pr comments

* updat reference

* Updating a skill

* Migrating Datacloud skills

* Migrating Industries cloud skills

* Validating - skills fixing

---------

Co-authored-by: Sandip Kumar Yadav <sandipkumar.yadav+sfemu@salesforce.com>
2026-05-14 19:32:15 +05:30

276 lines
11 KiB
JavaScript

/**
* FORM LWC COMPONENT TEMPLATE
*
* This template demonstrates a form component with:
* - lightning-record-edit-form for standard forms
* - Custom validation
* - Imperative Apex submission
* - Toast notifications
*
* Replace: formComponent → yourComponentName
* Replace: FormComponent → YourComponentName
*/
import { LightningElement, api, wire } from 'lwc';
import { getObjectInfo } from 'lightning/uiObjectInfoApi';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { NavigationMixin } from 'lightning/navigation';
import saveRecord from '@salesforce/apex/FormComponentController.saveRecord';
// Import schema for field references
import ACCOUNT_OBJECT from '@salesforce/schema/Account';
import NAME_FIELD from '@salesforce/schema/Account.Name';
import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry';
import PHONE_FIELD from '@salesforce/schema/Account.Phone';
export default class FormComponent extends NavigationMixin(LightningElement) {
// ═══════════════════════════════════════════════════════════════════════
// PUBLIC API
// ═══════════════════════════════════════════════════════════════════════
@api recordId; // For edit mode
@api objectApiName = 'Account';
// ═══════════════════════════════════════════════════════════════════════
// PRIVATE PROPERTIES
// ═══════════════════════════════════════════════════════════════════════
isLoading = false;
recordTypeId;
// Field values for custom form
formData = {
Name: '',
Industry: '',
Phone: ''
};
// ═══════════════════════════════════════════════════════════════════════
// SCHEMA REFERENCES
// ═══════════════════════════════════════════════════════════════════════
accountObject = ACCOUNT_OBJECT;
nameField = NAME_FIELD;
industryField = INDUSTRY_FIELD;
phoneField = PHONE_FIELD;
// ═══════════════════════════════════════════════════════════════════════
// WIRE SERVICE
// ═══════════════════════════════════════════════════════════════════════
@wire(getObjectInfo, { objectApiName: ACCOUNT_OBJECT })
objectInfo({ data, error }) {
if (data) {
// Get default record type
this.recordTypeId = data.defaultRecordTypeId;
}
}
// ═══════════════════════════════════════════════════════════════════════
// GETTERS
// ═══════════════════════════════════════════════════════════════════════
get isEditMode() {
return !!this.recordId;
}
get cardTitle() {
return this.isEditMode ? 'Edit Account' : 'New Account';
}
get submitButtonLabel() {
return this.isEditMode ? 'Save' : 'Create';
}
// ═══════════════════════════════════════════════════════════════════════
// LIGHTNING-RECORD-EDIT-FORM HANDLERS
// ═══════════════════════════════════════════════════════════════════════
/**
* Called when the form loads successfully
*/
handleLoad(event) {
this.isLoading = false;
console.log('Form loaded', event.detail);
}
/**
* Called when the record is saved successfully
*/
handleSuccess(event) {
this.isLoading = false;
const recordId = event.detail.id;
const recordName = event.detail.fields.Name.value;
this.showToast(
'Success',
`Account "${recordName}" ${this.isEditMode ? 'updated' : 'created'} successfully`,
'success'
);
// Dispatch event for parent components
this.dispatchEvent(new CustomEvent('save', {
detail: { recordId, recordName }
}));
// Navigate to record page
if (!this.isEditMode) {
this.navigateToRecord(recordId);
}
}
/**
* Called when there's an error saving
*/
handleError(event) {
this.isLoading = false;
const errorMessage = event.detail.message || 'An error occurred';
this.showToast('Error', errorMessage, 'error');
console.error('Form error:', event.detail);
}
/**
* Called before the form submits - opportunity to validate
*/
handleSubmit(event) {
event.preventDefault(); // Stop default submission
// Custom validation
const fields = event.detail.fields;
if (!this.validateForm(fields)) {
return;
}
this.isLoading = true;
// Modify fields if needed before submission
// fields.Custom_Field__c = 'Computed Value';
// Submit the form
this.template.querySelector('lightning-record-edit-form').submit(fields);
}
// ═══════════════════════════════════════════════════════════════════════
// CUSTOM FORM HANDLERS (Alternative to lightning-record-edit-form)
// ═══════════════════════════════════════════════════════════════════════
handleInputChange(event) {
const field = event.target.name || event.target.dataset.field;
const value = event.target.value;
this.formData = { ...this.formData, [field]: value };
}
async handleCustomSubmit() {
if (!this.validateCustomForm()) {
return;
}
this.isLoading = true;
try {
const result = await saveRecord({
recordData: JSON.stringify(this.formData),
recordId: this.recordId
});
this.showToast('Success', 'Record saved successfully', 'success');
this.dispatchEvent(new CustomEvent('save', {
detail: { recordId: result.Id }
}));
} catch (error) {
const errorMessage = error.body?.message || error.message || 'Unknown error';
this.showToast('Error', errorMessage, 'error');
} finally {
this.isLoading = false;
}
}
// ═══════════════════════════════════════════════════════════════════════
// VALIDATION
// ═══════════════════════════════════════════════════════════════════════
validateForm(fields) {
// Custom validation logic
if (fields.Name && fields.Name.length < 2) {
this.showToast('Validation Error', 'Name must be at least 2 characters', 'error');
return false;
}
// Validate all input fields
const allValid = [...this.template.querySelectorAll('lightning-input-field')]
.reduce((validSoFar, inputField) => {
inputField.reportValidity();
return validSoFar && inputField.checkValidity();
}, true);
return allValid;
}
validateCustomForm() {
const inputFields = this.template.querySelectorAll('lightning-input, lightning-combobox');
let isValid = true;
inputFields.forEach(field => {
if (!field.checkValidity()) {
field.reportValidity();
isValid = false;
}
});
return isValid;
}
// ═══════════════════════════════════════════════════════════════════════
// BUTTON HANDLERS
// ═══════════════════════════════════════════════════════════════════════
handleCancel() {
// Reset form
const inputFields = this.template.querySelectorAll('lightning-input-field');
inputFields.forEach(field => {
field.reset();
});
this.dispatchEvent(new CustomEvent('cancel'));
}
handleReset() {
const inputFields = this.template.querySelectorAll('lightning-input-field');
inputFields.forEach(field => {
field.reset();
});
}
// ═══════════════════════════════════════════════════════════════════════
// NAVIGATION
// ═══════════════════════════════════════════════════════════════════════
navigateToRecord(recordId) {
this[NavigationMixin.Navigate]({
type: 'standard__recordPage',
attributes: {
recordId: recordId,
objectApiName: this.objectApiName,
actionName: 'view'
}
});
}
// ═══════════════════════════════════════════════════════════════════════
// UTILITIES
// ═══════════════════════════════════════════════════════════════════════
showToast(title, message, variant) {
this.dispatchEvent(new ShowToastEvent({
title,
message,
variant
}));
}
}