mirror of
https://github.com/forcedotcom/afv-library.git
synced 2026-07-30 03:09:50 +08:00
276 lines
11 KiB
JavaScript
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
|
|
}));
|
|
}
|
|
}
|