Intermediate 30 min read

Project: Account/Contact Management Without Apex

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

  • Build a working Account and Contact management interface using only Lightning Data Service
  • Combine wire reads with imperative writes in one cohesive component
  • Apply reactive refresh so the UI never shows stale data after a change

Prerequisites: "Reactive Wire Parameters and Refreshing Data"

What We're Building

An accountManager component that:

  1. Displays a list of Accounts (via @wire and a SOQL-free UI API call — Module 20's capstone revisits combining this with Apex for more complex querying).
  2. Lets the user select an Account to view its Contacts.
  3. Lets the user add a new Contact to the selected Account using createRecord.

Every single piece of this uses Lightning Data Service — no Apex class anywhere.

Displaying the Selected Account's Details

import { LightningElement, wire } from 'lwc';
import { getRecord, getFieldValue } from 'lightning/uiRecordApi';
import NAME_FIELD from '@salesforce/schema/Account.Name';
import INDUSTRY_FIELD from '@salesforce/schema/Account.Industry';

export default class AccountManager extends LightningElement {
    selectedAccountId;

    @wire(getRecord, { recordId: '$selectedAccountId', fields: [NAME_FIELD, INDUSTRY_FIELD] })
    account;

    get accountName() {
        return getFieldValue(this.account.data, NAME_FIELD);
    }
}

Using '$selectedAccountId' as a reactive parameter (Lesson 5) means simply changing selectedAccountId automatically re-fetches the newly selected Account — no manual refresh call needed for this part.

Adding a New Contact

import { createRecord } from 'lightning/uiRecordApi';
import CONTACT_OBJECT from '@salesforce/schema/Contact';
import FIRST_NAME_FIELD from '@salesforce/schema/Contact.FirstName';
import LAST_NAME_FIELD from '@salesforce/schema/Contact.LastName';
import ACCOUNT_FIELD from '@salesforce/schema/Contact.AccountId';

async handleAddContact() {
    const recordInput = {
        apiName: CONTACT_OBJECT.objectApiName,
        fields: {
            [FIRST_NAME_FIELD.fieldApiName]: this.newFirstName,
            [LAST_NAME_FIELD.fieldApiName]: this.newLastName,
            [ACCOUNT_FIELD.fieldApiName]: this.selectedAccountId,
        },
    };

    try {
        await createRecord(recordInput);
        // refresh whatever component/wire lists this Account's Contacts
    } catch (error) {
        this.error = error;
    }
}

Setting ACCOUNT_FIELD.fieldApiName (AccountId) on the new Contact is what associates it with the currently selected Account — plain relational data, no Apex needed to establish it.

What This Project Proves

This is the module's entire thesis, demonstrated: reading records (@wire/getRecord), writing new ones (createRecord), and correctly refreshing the UI afterward (reactive parameters and refreshApex) — a genuinely complete, production-viable CRUD interface with zero Apex classes to write, deploy, or test.

Exercise

Write the reactive @wire declaration for fetching Contacts related to the selected Account (assume a getContactsForAccount UI API-friendly wire adapter exists with a recordId parameter).

Show hint

Follow the same $-prefixed pattern used throughout this module.

JAVASCRIPT

Exercise

Challenge: after successfully creating a new Contact, the Contacts list doesn't show it yet. Explain why, and what to add.

Show hint

Recall the distinction between reactive parameters and refreshApex.

JAVASCRIPT

Project: Account/Contact Management Without Apex Quiz

1. How many Apex classes does this project require?

2. What makes the Account detail section automatically update when a different Account is selected?

3. Creating a new Contact via createRecord automatically refreshes every other wired list on the page.

4. What field associates a new Contact with the currently selected Account?

5. What does this project demonstrate as its central point?

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 hands-on capstone proving the whole module's thesis: real, working record management — read, create, update — entirely without a single line of Apex.