Advanced 40 min read

Project: Lead Management Application

By the end of this lesson, you'll be able to:

  • Combine a datatable, a record form, and LDS create into one cohesive Lead management feature
  • Refresh a list after a related create operation
  • Apply this course's form validation and toast feedback patterns together

Prerequisites: Module 18: "Project: Convert a Desktop Component to Responsive"

What We're Building

A leadManager component with a lightning-datatable (Module 10) listing open Leads, and a "New Lead" form (Module 8's reportValidity() pattern) that creates a Lead via createRecord (Module 6) and refreshes the list on success.

The Component

import { LightningElement, wire } from 'lwc';
import { createRecord } from 'lightning/uiRecordApi';
import { refreshApex } from '@salesforce/apex';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import getOpenLeads from '@salesforce/apex/LeadController.getOpenLeads';
import LEAD_OBJECT from '@salesforce/schema/Lead';
import COMPANY_FIELD from '@salesforce/schema/Lead.Company';
import LAST_NAME_FIELD from '@salesforce/schema/Lead.LastName';

const COLUMNS = [
    { label: 'Name', fieldName: 'name', type: 'text', sortable: true },
    { label: 'Company', fieldName: 'company', type: 'text', sortable: true },
    { label: 'Status', fieldName: 'status', type: 'text' },
];

export default class LeadManager extends LightningElement {
    columns = COLUMNS;
    company = '';
    lastName = '';
    isSaving = false;
    wiredLeadsResult;

    @wire(getOpenLeads)
    wiredLeads(result) {
        this.wiredLeadsResult = result;
    }

    get leads() {
        return this.wiredLeadsResult?.data ?? [];
    }

    isFormValid() {
        return [...this.template.querySelectorAll('lightning-input')]
            .reduce((valid, field) => field.reportValidity() && valid, true);
    }

    async handleCreateLead() {
        if (!this.isFormValid()) {
            return;
        }

        this.isSaving = true;
        try {
            await createRecord({
                apiName: LEAD_OBJECT.objectApiName,
                fields: {
                    [COMPANY_FIELD.fieldApiName]: this.company,
                    [LAST_NAME_FIELD.fieldApiName]: this.lastName,
                },
            });
            await refreshApex(this.wiredLeadsResult);
            this.dispatchEvent(new ShowToastEvent({ title: 'Lead Created', variant: 'success' }));
        } catch (error) {
            this.dispatchEvent(new ShowToastEvent({
                title: 'Could Not Create Lead',
                message: error.body?.message ?? 'An unexpected error occurred.',
                variant: 'error',
            }));
        } finally {
            this.isSaving = false;
        }
    }
}

getOpenLeads follows Module 16's thin-Controller pattern; refreshApex(this.wiredLeadsResult) (Module 6) is what makes the newly created Lead appear in the datatable without a manual reload.

Exercise

Explain, as a comment, why refreshApex is needed after createRecord succeeds, even though createRecord itself already succeeded.

Show hint

Recall Module 6's reactive refresh lesson.

JAVASCRIPT

Exercise

Challenge: add a Phone field (not required) to the create form and its handler.

Show hint

Follow the same pattern as company/lastName.

JAVASCRIPT

Project: Lead Management Application Quiz

1. What refreshes the Lead datatable after a new Lead is created?

2. What does isFormValid() do before allowing the create to proceed?

3. What creates the new Lead record?

4. What does isSaving control?

5. What pattern from Module 16 does getOpenLeads's Apex Controller follow?

Log in to submit the quiz and save your score.

My Notes

Log in to keep private notes on this lesson.

Questions about this lesson

No questions yet — be the first to ask.

Log in to ask a question about this lesson.

Summary

A full Lead management feature — a searchable, sortable list plus a validated creation form — synthesizing Lightning Data Service (Module 6), datatables (Module 10), and forms (Module 8) into one realistic application.