Top Salesforce LWC Scenario-Based Interview Questions and Answers
Hello Everyone,
If you are preparing for Salesforce Lightning Web Components (LWC) interviews, you should know that the way questions are asked has changed a lot over the years. Earlier, interviews focused mostly on theory and direct definitions like "What is LWC?" or "How is LWC different from Aura?". These were easy to memorize and answer.
Today, interviewers expect much more. Instead of just checking your theoretical knowledge, they focus on real-time scenarios and how you would solve practical problems while working on actual projects. The idea is to test your hands-on experience, problem-solving approach, and how well you understand the framework in real situations.
In this guide, I'll walk you through some of the most common scenario-based LWC interview questions along with explanations and examples. These will not only help you understand the concepts but also prepare you to explain them clearly to interviewers, just like you would in a real conversation.
Let's get started with the scenario-based questions and answers.
Scenario-1: You need to create a list of records with inline editing (similar to the standard datatable) and save changes in bulk.
- How would you implement inline editing in LWC?
- How would you track modified rows and handle bulk save via Apex?
- What would you do to ensure rollback in case of partial failures?
Answer – I'll explain how to implement inline editing in LWC, track modified rows, handle bulk save via Apex, and ensure rollback for partial failures.
1. How would you implement inline editing in LWC?
- Salesforce provides
lightning-datatable
which supports inline editing using theeditable
property. - When a user edits a cell, the event
onsave
oroncellchange
is fired. - I would capture those draft values (
event.detail.draftValues
) and track them in my component. - These draft values are then sent to Apex for bulk update.
Code Example:
HTML Template
<template> <lightning-card title="Accounts Inline Edit"> <lightning-datatable key-field="Id" data={accounts} columns={columns} draft-values={draftValues} onsave={handleSave} hide-checkbox-column="true"> </lightning-datatable> </lightning-card> </template>
JavaScript Controller
//inlineEditAccounts.js import { LightningElement, track, wire } from 'lwc'; import getAccounts from '@salesforce/apex/AccountController.getAccounts'; import updateAccounts from '@salesforce/apex/AccountController.updateAccounts'; import { ShowToastEvent } from 'lightning/platformShowToastEvent'; export default class InlineEditAccounts extends LightningElement { @track accounts = []; @track draftValues = []; columns = [ { label: 'Name', fieldName: 'Name', editable: true }, { label: 'Industry', fieldName: 'Industry', editable: true }, { label: 'Phone', fieldName: 'Phone', editable: true } ]; @wire(getAccounts) wiredAccounts({ data, error }) { if (data) { this.accounts = data; } else if (error) { console.error(error); } } handleSave(event) { const records = event.detail.draftValues.map(draft => { return { ...draft }; // shallow copy }); updateAccounts({ accList: records }) .then(() => { this.showToast('Success', 'Records updated successfully', 'success'); this.draftValues = []; return refreshApex(this.wiredAccounts); }) .catch(error => { this.showToast('Error updating records', error.body.message, 'error'); }); } showToast(title, message, variant) { this.dispatchEvent(new ShowToastEvent({ title, message, variant })); } }
OutPut:
2. How would you track modified rows and handle bulk save via Apex?
- The
draftValues
array automatically holds only modified rows, not the full dataset. - When a user edits a cell, the event
onsave
oroncellchange
is fired. - I can pass this list directly to Apex.
- In Apex, I would perform a bulk update using a try-catch.
Apex Example:
// Apex class (AccountController) public with sharing class AccountController { @AuraEnabled(cacheable=true) public static List<Account> getAccounts() { return [SELECT Id, Name, Industry, Phone FROM Account LIMIT 50]; } @AuraEnabled public static void updateAccounts(List<Account> accList) { try { update accList; } catch (DmlException e) { throw new AuraHandledException('Error updating accounts: ' + e.getMessage()); } } }
3. What would you do to ensure rollback in case of partial failures?
- By default,
update accList;
does an all-or-nothing DML (if one fails, all fail). - But in some cases, we might want partial success handling.
- To handle this:
- Use
Database.update(records, false)
—> allows partial success. - Process the
Database.SaveResult[]
to find which records failed and send back error messages to the UI. - If the requirement is true rollback, then I would just use a single
update accList;
inside a try-catch so either all succeed or all fail.
Apex Example with Partial Success:
@AuraEnabled public static List<String> updateAccounts(List<Account> accList) { List<String> errors = new List<String>(); Database.SaveResult[] results = Database.update(accList, false); for (Integer i = 0; i < results.size(); i++) { if (!results[i].isSuccess()) { errors.add('Failed to update record ' + accList[i].Id + ': ' + results[i].getErrors()[0].getMessage()); } } return errors; // return errors to LWC }
LWC Handling Partial Failures:
updateAccounts({ accList: records }) .then(errors => { if (errors.length > 0) { this.showToast('Partial Success', errors.join(', '), 'warning'); } else { this.showToast('Success', 'All records updated', 'success'); } this.draftValues = []; return refreshApex(this.wiredAccounts); }) .catch(error => { this.showToast('Error', error.body.message, 'error'); });
MIND IT !
Final Interview-Ready Answer (Short Wrap-up)
- Use
lightning-datatable
witheditable=true
for inline editing. - Track modified rows with
draftValues
and send only those to Apex. - In Apex, perform bulk DML updates.
- For rollback:
- Use default DML (
update accList;
) if all-or-nothing is required. - Use
Database.update(records, false)
for partial success and handle errors gracefully in LWC.
Scenario-2: You want to add links in your LWC that navigate the user to specific Lightning pages like a record page, app page, or external URL.
- How would you implement deep linking in LWC?
- How do you use NavigationMixin for different destinations?
- What are the limitations of navigation in Communities?
Answer – Implementing navigation is a fundamental part of building intuitive Lightning experiences. The standard and most robust way to handle deep linking in LWC is by using the Lightning Navigation Service
, specifically the NavigationMixin
.
1. What is Deep Linking?
Deep linking simply means using a URL to link directly to a specific piece of content within an app, rather than just its homepage. In the Salesforce context, this means linking directly to a record, an app page, a list view, or even a specific tab within the Salesforce UI.
2. How would you implement deep linking in LWC? How do you use NavigationMixin?
- In LWC, we use the
NavigationMixin
module to handle navigation instead of hardcoding URLs. - It allows us to navigate to record pages, object pages, Lightning apps, web pages, and more, using pageReference objects.
- The structure of this pageReference changes based on the destination.
- Deep linking means constructing those references dynamically (like recordId, objectApiName, action).
Let me break down the implementation for the most common destinations.
Code Implementation Examples
First, import and apply the mixin in your JavaScript file:
// navigationExample.js import { LightningElement } from 'lwc'; // 1. Import the NavigationMixin import { NavigationMixin } from 'lightning/navigation'; // 2. Apply the Mixin to your class export default class NavigationExample extends NavigationMixin(LightningElement) { handleNavigateToRecord() { // Example methods shown below will go here } }
a) Navigate to a Record Page
This is the most common use case. The page reference requires the record ID and the type of page view (e.g., 'view').
navigateToRecordView() { this[NavigationMixin.Navigate]({ type: 'standard__recordPage', attributes: { recordId: '001XXXXXXXXXXXXXXX', // Replace with a real Id actionName: 'view' // Can also be 'edit' or 'clone' } }); }
b) Navigate to an App Page (Home Page, App Home)
This is useful for linking to the Home tab or a specific app's landing page. You need the pageName
or the API name of the app.
navigateToHomePage() { this[NavigationMixin.Navigate]({ type: 'standard__namedPage', attributes: { pageName: 'home' // Other common values: 'objectHome', 'listView' } }); } navigateToSalesApp() { this[NavigationMixin.Navigate]({ type: 'standard__appPage', attributes: { name: 'Sales' // The API name of the Salesforce App } }); }
c) Navigate to an Object Home Page (List Views)
This navigates to the tab for a specific object, like the list of all Accounts.
navigateToAccountHome() { this[NavigationMixin.Navigate]({ type: 'standard__objectPage', attributes: { objectApiName: 'Account', actionName: 'list' // For list views } }); }
d) Navigate to a Custom Web Page (External URL)
For external URLs, you use a different page reference type. This will open the link in a new tab by default, which is a security best practice.
navigateToExternalUrl() { this[NavigationMixin.Navigate]({ type: 'standard__webPage', attributes: { url: 'https://www.learnfrenzy.com' } }); } // To open in the same tab, add a 'state' object with a 'channel' property (less common due to UX best practices).
e) Generate a URL (Without Navigating Immediately)
Sometimes you need the URL itself, for example, to use in an <a> tag or to display to the user. You can use the generateUrl method for this.
async getRecordUrl() { // Generate a URL for a record page const url = await this[NavigationMixin.GenerateUrl]({ type: 'standard__recordPage', attributes: { recordId: '001XXXXXXXXXXXXXXX', actionName: 'view' } }); console.log(url); // Use this URL as needed }
3. What are the limitations of navigation in Communities (Experience Cloud)?
This is a critical point. While NavigationMixin
works in Communities, its behavior is different and has important limitations compared to the internal Salesforce org.
- Different Page References: The
standard__recordPage
andstandard__objectPage
references do not work in Communities. Communities uses its own unique set of page reference types based on the Community's page structure. - Dependency on URL Rewriting: Communities relies on friendly URLs. To navigate, you must use the Community's specific path structure. The
NavigationMixin
abstracts this, but you must use the correct page reference types. - Correct Page Reference Types for Communities:
- Record Page: Use
standard__recordPage
is not available. Instead, you must use the Communities-specific page type, often by targeting the page's API name. - Common Community Page Types:
standard__namedPage
withpageName: 'home'
(for the community home)standard__knowledgeArticlePage
(for Knowledge)- Most importantly, you often navigate to a specific
Page
in the community. You need to know the API name of the Community Page you want to link to.
// Example: Navigating to a Record Page in a Community navigateToRecordInCommunity() { this[NavigationMixin.Navigate]({ // This is the key difference type: 'comm__namedPage', attributes: { // You must know the API name of the target page in your Community name: 'product_details__c' }, // You pass the recordId as a state parameter state: { recordId: 'a02XXXXXXXXXXXXXXX' } }); }
4. How to Handle It:
The most reliable way to build navigation for both org and community is to use Base Lightning Components like <lightning-button>
with an onclick
handler that uses the NavigationMixin
. The mixin is smart enough to use the correct underlying URL structure based on the context (Org vs. Community). Hardcoding URLs is a major maintenance headache and will break.
MIND IT !
Final Interview-Ready Wrap-Up
- Use NavigationMixin.Navigate for deep linking in LWC.
- Construct different
pageReference
objects depending on the destination (record, list view, app, web). - In Communities, some navigation types (like
standard__app
) aren’t supported, and links must remain within the Community domain.
Scenario-3: A client wants custom sorting logic in a lightning-datatable, especially for dates and picklists.
- How would you implement client-side and server- side sorting?
- How do you handle sorting with formatted fields like currency and date?
- Can the lightning-datatable handle complex nested object sorting?
Answer – That's a common requirement, as the default alphabetical sorting doesn't work for specialized data types like dates or picklists with custom value orders. The lightning-datatable provides a hook for custom sorting, and we can implement it either on the client-side for performance or on the server-side for large datasets.
1. How would you implement client-side and server-side sorting?
- Client-side sorting: If the dataset is small and already loaded into LWC, I can override the
onsort
event handler oflightning-datatable
. - The event provides
fieldName
andsortDirection
. - I can write custom JS logic to sort the array.
- Server-side sorting: If the dataset is large (thousands of rows, pagination, or SOQL), I would pass the sort field and direction to Apex, and let SOQL do the sorting.
- Example:
ORDER BY CreatedDate DESC
. - Then return the sorted result to LWC.
Client-side Example:
<lightning-datatable key-field="Id" data={data} columns={columns} onsort={handleSort} sorted-by={sortedBy} sorted-direction={sortedDirection} hide-checkbox-column="true"> </lightning-datatable>
handleSort(event) { const { fieldName: sortedBy, sortDirection } = event.detail; const cloneData = [...this.data]; cloneData.sort((a, b) => { let valA = a[sortedBy] ? a[sortedBy].toString().toLowerCase() : ''; let valB = b[sortedBy] ? b[sortedBy].toString().toLowerCase() : ''; return sortDirection === 'asc' ? valA > valB ? 1 : -1 : valA < valB ? 1 : -1; }); this.data = cloneData; this.sortedBy = sortedBy; this.sortedDirection = sortDirection; }
Server-side Example (Apex SOQL):
@AuraEnabled(cacheable=true) public static List<account> getAccounts(String sortField, String sortDir) { String query = 'SELECT Id, Name, Industry, CreatedDate FROM Account ' + 'ORDER BY ' + sortField + ' ' + sortDir + ' LIMIT 200'; return Database.query(query); }
2. How do you handle sorting with formatted fields like currency and date?
- For Currency:
- Convert the value to
Number
before sorting. - Example:
parseFloat(record.AnnualRevenue)
so sorting works numerically, not alphabetically. - For Date/Datetime:
- Convert the string into a
Date
object (new Date(record.CreatedDate)
) and sort numerically by timestamp.
Example: Custom sort for Date and Currency
cloneData.sort((a, b) => { let valA = a[sortedBy], valB = b[sortedBy]; if (sortedBy === 'AnnualRevenue') { valA = parseFloat(valA) || 0; valB = parseFloat(valB) || 0; } if (sortedBy === 'CreatedDate') { valA = new Date(valA).getTime(); valB = new Date(valB).getTime(); } return sortDirection === 'asc' ? valA - valB : valB - valA; });
That way, the sort respects numerical values instead of treating them as strings.
3. Can the lightning-datatable handle complex nested object sorting?
- By default,
lightning-datatable
does not support sorting on nested objects (Account.Owner.Name
for example). - Workarounds:
- Flatten the data in Apex: Query with a relationship and expose it as a simple field alias. Example:
Owner.Name
—>OwnerName
. - Transform the data in JS: Before binding to datatable, restructure records into a flat format.
Example (Flatten in Apex):
SELECT Id, Name, Owner.Name, Owner.Email FROM Account
Transform in Apex:
List<accountwrapper> results = new List<accountwrapper>(); for (Account acc : [SELECT Id, Name, Owner.Name FROM Account]) { results.add(new AccountWrapper(acc.Id, acc.Name, acc.Owner.Name)); }
public class AccountWrapper { @AuraEnabled public Id Id { get; set; } @AuraEnabled public String Name { get; set; } @AuraEnabled public String OwnerName { get; set; } public AccountWrapper(Id id, String name, String ownerName) { Id = id; Name = name; OwnerName = ownerName; } }
Now sort simply on OwnerName
.
MIND IT !
Final Interview-Ready Wrap-Up
- Use
onsort
for client-side sorting (good for small datasets). - Use Apex + ORDER BY for server-side sorting (scalable for large datasets).
- For formatted fields (currency/date), always convert to numeric or Date objects before comparing.
lightning-datatable
cannot handle nested fields directly — flatten data in Apex or transform it in JS before binding.
Scenario-4: Two users are trying to edit the same record in your LWC component at the same time.
- How would you prevent one user from overriding another user’s changes?
- What is the difference between optimistic locking and pessimistic locking in Salesforce?
- How can you notify users about conflicting changes?
Answer – That's a critical scenario that deals with data integrity. When two users edit the same record simultaneously, the last user to save wins, silently overwriting the first user's changes. This is called a 'lost update' problem. To prevent this, Salesforce provides mechanisms for both Optimistic and Pessimistic Locking.
1. How would you prevent one user from overriding another user’s changes?
In Salesforce, when two users edit the same record at the same time, the default mechanism is optimistic locking. Salesforce uses a hidden field called SystemModstamp
or LastModifiedDate
. When I try to update the record from LWC (through Apex), Salesforce checks if the LastModifiedDate
matches the current database value.
- If it matches —> Update succeeds.
- If it doesn’t —> Salesforce throws a
DmlException
(FIELD_INTEGRITY_EXCEPTION
), meaning someone else already updated the record.
So in my LWC + Apex, I would:
- Always fetch the latest record before editing.
- When saving, include
Id
andLastModifiedDate
in the update payload. - Catch the exception in Apex and notify the user in LWC.
Code Example:
// Apex Controller public with sharing class AccountController { @AuraEnabled public static void updateAccount(Account acc) { try { update acc; // Will fail if LastModifiedDate mismatch } catch (DmlException e) { throw new AuraHandledException('Record has been modified by another user. Please refresh.'); } } }
// LWC JS import { LightningElement, track, api } from 'lwc'; import updateAccount from '@salesforce/apex/AccountController.updateAccount'; import { ShowToastEvent } from 'lightning/platformShowToastEvent'; export default class AccountEditor extends LightningElement { @track accountRecord; handleSave() { updateAccount({ acc: this.accountRecord }) .then(() => { this.showToast('Success', 'Record updated successfully', 'success'); }) .catch(error => { this.showToast('Error', error.body.message, 'error'); }); } showToast(title, message, variant) { this.dispatchEvent(new ShowToastEvent({ title, message, variant })); } }
This way, the system prevents overwriting silently.
2. What is the difference between optimistic locking and pessimistic locking in Salesforce?
Optimistic Locking (default in Salesforce):
- Assumes conflicts are rare.
- Multiple users can read the same record.
- On save, Salesforce checks
LastModifiedDate
. If mismatch, update fails. - This is lightweight, default, and works best for most business processes.
Pessimistic Locking (explicitly using FOR UPDATE
):
- One user locks the record during transaction (SOQL query with
FOR UPDATE
). - Other users cannot update the record until lock is released.
- On save, Salesforce checks LastModifiedDate. If mismatch, update fails.
- Useful when high chance of conflicts (like financial transactions or inventory systems).
Example:
// Locking a record explicitly Account acc = [SELECT Id, Name FROM Account WHERE Id = :recordId FOR UPDATE]; // This prevents others from editing until transaction commits
3. How can you notify users about conflicting changes?
There are a couple of strategies:
- Toast/Error Message in LWC:
- If optimistic locking fails, catch the DML exception and show a clear message like:
“This record was updated by another user. Please refresh to see the latest changes.” - Highlight Changes Before Save:
- Compare record data in LWC with the latest fetched from Apex before committing update.
- If fields differ, show a UI diff popup: “Field X was changed from A —> B by another user.”
- Platform Events / Streaming API:
- Subscribe to record changes via Change Data Capture (CDC) or Platform Events.
- Notify the user in real-time if the record they’re editing has been modified elsewhere.
Example for Change Notification:
// LWC subscribing to Account CDC import { subscribe, MessageContext } from 'lightning/empApi'; connectedCallback() { this.subscription = subscribe('/data/AccountChangeEvent', -1, (message) => { this.showToast('Record Updated', 'This record was modified by another user. Please refresh.', 'warning'); }); }
MIND IT !
Final Interview Style Answer Wrap-Up:
- I would rely on optimistic locking (default in Salesforce) to prevent overwriting.
- If needed, use pessimistic locking with
FOR UPDATE
for critical transactions. - To notify users, I’d catch exceptions in Apex and show a toast in LWC, or implement real-time notifications with CDC for a smoother experience.
A sample real-time LWC UI flow diagram (like how User A and User B interact with the record, and where conflict happens)
Scenario-5: You're displaying a list of 1000+ items in an LWC. The client complains about poor performance.
- How do you implement virtual scrolling or lazy loading?
- Can LWC natively handle virtual lists?
- What are the alternatives to reduce rendering lag?
Answer – We have two primary strategies: Infinite Loading (Lazy Loading) and true Virtual Scrolling. I would almost always recommend Lazy Loading for this scenario.
1. How do you implement virtual scrolling or lazy loading?
- Virtual Scrolling: Instead of rendering all 1000 records at once, you render only the visible portion of the list plus a buffer. As the user scrolls, more rows are loaded and older ones are discarded from the DOM.
- LWC does not have built-in virtual scrolling, so you implement it manually using JavaScript scroll events or leverage a
lightning-datatable
with lazy loading.
Example: Lazy Loading in lightning-datatable
:
<template> <lightning-card title="Lazy Loading Example"> <lightning-datatable key-field="Id" data={data} columns={columns} onloadmore={handleLoadMore} enable-infinite-loading is-loading={isLoading}> </lightning-datatable> </lightning-card> </template>
//lazyLoadDatatable.js import { LightningElement, track } from 'lwc'; import getAccounts from '@salesforce/apex/AccountController.getAccounts'; import getTotalAccounts from '@salesforce/apex/AccountController.getTotalAccounts'; export default class LazyLoadDatatable extends LightningElement { @track data = []; @track columns = [ { label: 'Account Name', fieldName: 'Name' }, { label: 'Industry', fieldName: 'Industry' }, { label: 'Phone', fieldName: 'Phone', type: 'phone' }, { label: 'Type', fieldName: 'Type' } ]; rowLimit = 20; // load 20 at a time rowOffset = 0; totalRecords = 0; connectedCallback() { this.loadTotalRecords(); } loadTotalRecords() { getTotalAccounts().then(count => { this.totalRecords = count; this.loadData(); }); } loadData() { getAccounts({ offsetSize: this.rowOffset, limitSize: this.rowLimit }) .then(result => { this.data = [...this.data, ...result]; this.rowOffset = this.data.length; }) .catch(error => { console.error('Error loading accounts', error); }); } handleLoadMore(event) { if (this.data.length >= this.totalRecords) { event.target.isLoading = false; return; } this.loadData(); event.target.isLoading = false; } }
Apex Controller:
public with sharing class AccountController { @AuraEnabled(cacheable=true) public static List<Account> getAccounts(Integer offsetSize, Integer limitSize) { return [ SELECT Id, Name, Industry, Phone, Type FROM Account ORDER BY LastModifiedDate DESC LIMIT :limitSize OFFSET :offsetSize ]; } @AuraEnabled(cacheable=true) public static Integer getTotalAccounts() { return [SELECT COUNT() FROM Account]; } }
Output:
- When the user opens this component, it initially shows 20 Accounts.
- As the user scrolls down, it fetches the next 20 Accounts from the server.
- If there are 5,000 Accounts, the user will eventually see all, but only a small chunk is ever loaded in memory at once.
- This makes the UI fast, smooth, and scalable.
2. Can LWC natively handle virtual lists?
- No. LWC doesn’t provide a built-in virtual scroller like React or Angular CDK.
- You need to custom implement lazy loading or use Lightning Base Components such as:
lightning-datatable
withonloadmore
(infinite scroll for data tables).lightning-list-view
(for standard list views).- For non-datatable UI, you can implement lazy loading with Intersection Observer API or a "Load More" button.
3. What are the alternatives to reduce rendering lag?
- Pagination: Show 50–100 records per page instead of 1000.
- Lazy Loading: Load records only as the user scrolls down.
- Chunked Rendering: Render records in small batches with
requestAnimationFrame
to avoid blocking the UI. - Lightning Base Components: Use
lightning-datatable
instead of custom HTML for better optimized rendering. - Reduce DOM Complexity: Avoid deeply nested templates or unnecessary reactivity on large arrays.
- Caching: Use
@wire
withcacheable=true
for faster retrieval.
MIND IT !
Interview Tip for Candidate:
Explain that Salesforce recommends lazy loading or pagination because virtual scrolling is not built-in. Show you know both client-side techniques (chunked rendering, IntersectionObserver
) and server-side techniques (OFFSET in SOQL, Batch fetch). Mention performance tuning (limit reactivity, use key-field properly).
Scenario-6: You need to populate a dropdown in LWC with picklist values from a specific record type of an object.
- How do you get picklist values using getPicklistValuesByRecordType?
- How would you support both global and record- type-specific values?
- How do you handle dependent picklists?
Answer –
1. How do you get picklist values using getPicklistValuesByRecordType?
- In LWC, Salesforce provides
@wire(getPicklistValuesByRecordType, { objectApiName: ..., recordTypeId: ... })
from thelightning/uiObjectInfoApi
. - This returns all picklist values available for the given record type, including record-type-specific restrictions.
Example Code:
import { LightningElement, wire, track } from 'lwc'; import { getPicklistValuesByRecordType } from 'lightning/uiObjectInfoApi'; import ACCOUNT_OBJECT from '@salesforce/schema/Account'; export default class PicklistByRecordTypeExample extends LightningElement { @track industryOptions = []; recordTypeId = '012XXXXXXXXXXXX'; // replace with correct Record Type Id @wire(getPicklistValuesByRecordType, { objectApiName: ACCOUNT_OBJECT, recordTypeId: '$recordTypeId' }) picklistHandler({ data, error }) { if (data) { this.industryOptions = data.picklistFieldValues.Industry.values.map(val => ({ label: val.label, value: val.value })); } if (error) { console.error(error); } } }
2. How would you support both global and record-type-specific values?
- Global values: Some picklists (like
LeadSource
) are global, not restricted by record type. You can usegetPicklistValues
(not by record type). - Record-type-specific values: Use
getPicklistValuesByRecordType
. - Best practice: Check your use case. If you know the picklist is global —> use
getPicklistValues
. If it varies per record type —> usegetPicklistValuesByRecordType
.
3. How do you handle dependent picklists?
- Dependent picklists require:
- Controller field (ex: Industry)
- Dependent field (ex: Sub-Industry)
- Salesforce provides a
controllerValues
map in the response ofgetPicklistValuesByRecordType
. - Each dependent value has a
validFor
array that maps to controller values.
Example for dependent picklists:
@track industryOptions = []; @track subIndustryOptions = []; selectedIndustry; @wire(getPicklistValuesByRecordType, { objectApiName: ACCOUNT_OBJECT, recordTypeId: '$recordTypeId' }) picklistHandler({ data, error }) { if (data) { this.industryOptions = data.picklistFieldValues.Industry.values; this.subIndustryOptionsData = data.picklistFieldValues.Sub_Industry__c; } } handleIndustryChange(event) { this.selectedIndustry = event.detail.value; let controllerValue = this.subIndustryOptionsData.controllerValues[this.selectedIndustry]; this.subIndustryOptions = this.subIndustryOptionsData.values.filter(opt => opt.validFor.includes(controllerValue) ); }
MIND IT !
Key points to highlight in interview answer
- Use
getPicklistValuesByRecordType
for record-type-specific picklists. - For global picklists, use
getPicklistValues
. - Dependent picklists require filtering using
controllerValues
andvalidFor
. - Always handle error cases (e.g., missing recordTypeId or API name).
- This ensures your LWC works both in dynamic record-type scenarios and global picklist cases.
Scenario-7: You have a component displaying data that may be updated by other users. The client wants real- time updates without a manual refresh.
- How would you implement real-time updates in LWC?
- What are the differences between using @wire, Lightning Data Service, and Platform Events?
- How would you handle record locking or stale data?
Answer – For real-time updates in LWC, I would combine Lightning Data Service (LDS) with Platform Events or Change Data Capture (CDC) depending on the use case.
1. How would you implement real-time updates in LWC?
There are three main approaches:
- @wire with UI APIs (
getRecord
,getListUi
) - Provides automatic updates when the record changes in Salesforce (similar to Lightning Data Service).
- Best for single-record details or simple UI refresh.
- Lightning Data Service (LDS)
- Works behind the scenes to keep records in sync.
- If the same record is edited in another tab, the UI refreshes automatically without writing extra logic.
- Ideal for forms and single record components.
- Platform Events / Change Data Capture (CDC)
- Push model for real-time streaming updates.
- Subscribe to Salesforce events (via
empApi
module in LWC). - Best for multi-user collaborative views, dashboards, or lists where multiple users might edit data.
- Platform Events/CDC allow us to get real-time server-side updates when records are updated by other users.
In your case (multi-user updates on lists):
Use Change Data Capture with empApi subscription in LWC to refresh data in real time.
Example:
import { LightningElement, wire, track } from 'lwc'; import { subscribe, unsubscribe, onError } from 'lightning/empApi'; import getAccounts from '@salesforce/apex/AccountController.getAccounts'; export default class RealTimeAccountList extends LightningElement { @track accounts = []; subscription = {}; connectedCallback() { this.loadData(); this.subscribeToChangeEvent(); } loadData() { getAccounts().then(result => { this.accounts = result; }); } subscribeToChangeEvent() { const messageCallback = (response) => { console.log('Change event received: ', response); this.loadData(); // reload data when record is updated }; subscribe('/data/AccountChangeEvent', -1, messageCallback).then(resp => { this.subscription = resp; }); onError(error => console.error('EMP API error: ', error)); } disconnectedCallback() { unsubscribe(this.subscription, response => { console.log('Unsubscribed: ', response); }); } }
2. Differences between @wire, LDS, and Platform Events
- @wire with Apex:
- Good for fetching data from the server.
- But data is static unless re-fetched.
- Needs manual refresh (
refreshApex
) to show latest values. - Lightning Data Service (LDS):
- Provides cached data and auto-refresh when the same record is updated by other components in the Lightning framework.
- No Apex code needed.
- However, it does not push real-time updates across different sessions/users.
- Platform Events / Change Data Capture:
- Best choice for real-time updates across users.
- Allows subscribing to events when records change and pushing updates to the UI.
3. How would you handle record locking or stale data?
To handle stale data and record locking, I’d rely on Salesforce’s optimistic concurrency control and RecordEditForm
or Apex with FOR UPDATE
.
- Optimistic Locking:
Salesforce automatically prevents overwriting changes by using a LastModifiedDate
/SystemModstamp
.
If another user updates the record before my save, I’ll get a DmlException
. I can catch this in Apex and show a toast message in LWC:
"The record has been updated by another user. Please refresh and try again."
Example in Apex:
try { update recordsToSave; } catch (DmlException e) { // Handle stale record throw new AuraHandledException('Record has been modified by another user. Please refresh.'); }
If strict locking is needed, I can use FOR UPDATE in SOQL to lock the row while updating. Example:
Contact c = [SELECT Id, Email FROM Contact WHERE Id = :recordId FOR UPDATE]; c.Email = 'newemail@example.com'; update c;
MIND IT !
Final Wrap-up (How Candidate Should Close)
So, to summarize:
- For real-time updates, I would use Change Data Capture or Platform Events along with
refreshApex
to update UI. - For in-app record sync, I’d leverage Lightning Data Service.
- For fetching data with control, I’d use @wire with Apex.
- To handle record conflicts, I’d rely on Salesforce’s optimistic concurrency and
FOR UPDATE
when needed.
(0) Comments