Creating Custom Tabs for Lightning Web Components

Create a Lightning web component and add it as a custom tab in the App Launcher and navigation menu.

  • Create a new Lightning web component:
    • Name: myComponent
  • Add a lightning-card to myComponent:
    • Title: Hello
  • Add a lightning-button to the Hello lightning-card (Note: make sure the button lives in the “actions” slot):
    • Label: New
  • Add a footer paragraph to the Hello lightning-card:
    • Text: Footnote
  • Add myComponent as a new custom tab:
    • Name: Words

Before you begin, you must update the configuration file to allow for custom tabs.

Copy the following code and paste it into notepad and save it as myComponent.js-meta.xml

<?xml version=”1.0″ encoding=”UTF-8″?>
<LightningComponentBundle xmlns=”http://soap.sforce.com/2006/04/metadata”&gt;
<apiVersion>46.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<target>lightning__Tab</target>
</targets>
</LightningComponentBundle>

Use workbench to deploy the lightning component bundle to your org.

Editable Lightning Datatable Component

I wanted a nicer way to display related contacts on an account page layout.  This editable lightning datatable custom component does the trick!  I love it and it’s working out really well for us.

ContactDataTable Component

<aura:component implements=”force:appHostable,flexipage:availableForAllPageTypes,force:hasRecordId” access=”global” controller=”ContactDataTableController”>
<aura:attribute name=”data” type=”Object”/>
<aura:attribute name=”columns” type=”List”/>
<aura:attribute name=”recordId” type=”String”/>
<!– This attribute will hold the update records from data table–>
<aura:attribute name=”updatedRecord” type=”Object[]” />

<aura:handler name=”init” action=”{!c.doInit}” value=”{!this}”/>

<!– You must define keyField as ‘Id’ to save the record back in Salesforce ‘onsave’ attribute will executed when user clicks on save button –>
<!–<lightning:card >–>
<lightning:datatable
aura:id=”contactDataTable”
columns=”{! v.columns }”
data=”{! v.data }”
keyField=”Id”
onsave =”{!c.onSave}”
hideCheckboxColumn=”true”
onrowaction=”{! c.handleRowAction }” />
<!–</lightning:card>–>
</aura:component>

ContactDataTableController.js

({
/*
* This finction defined column header
* and calls getContacts helper method for column data
* editable:’true’ will make the column editable
* */
doInit : function(component, event, helper) {
component.set(‘v.columns’, [
{label: ‘Name Range’, fieldName: ‘Name_Range__c’, editable:’true’, type: ‘text’},
//{label: ‘Name’, fieldName: ‘Name’, editable:’true’, type: ‘text’},
{label: ‘Contact Name’, fieldName: ‘linkName’, type: ‘url’,
typeAttributes: {label: { fieldName: ‘Name’ }}},
{label: ‘Title’, fieldName: ‘Title’, editable:’true’, type: ‘text’},
{label: ‘Email’, fieldName: ‘Email’, editable:’true’, type: ’email’},
{label: ‘Phone’, fieldName: ‘Phone’, editable:’true’, type: ‘tel’},
{label: ‘Board Contact’, fieldName: ‘Board_Contact__c’, editable:’true’, type: ‘text’},

]);
helper.getContacts(component, helper);
},

/*
* This function is calling saveDataTable helper function
* to save modified records
* */
onSave : function (component, event, helper) {
helper.saveDataTable(component, event, helper);
}
})

ContactDataTableHelper.js

({
getContacts : function(component, event, helper) {
var action = component.get(“c.getContacts”);
action.setParams({
accountId: component.get(“v.recordId”)
//console.log(accountId)
});
action.setCallback(this,function(response) {
var state = response.getState();
if (state === “SUCCESS”) {
var records =response.getReturnValue();
component.set(“v.data”, response.getReturnValue());
records.forEach(function(record){
record.linkName = ‘/’+record.Id;
});
component.set(“v.data”, records);
}
});
$A.enqueueAction(action);
},

/*
* This function get called when user clicks on Save button
* user can get all modified records
* and pass them back to server side controller
* */
saveDataTable : function(component, event, helper) {
var editedRecords = component.find(“contactDataTable”).get(“v.draftValues”);
var totalRecordEdited = editedRecords.length;
var action = component.get(“c.updateContacts”);
action.setParams({
‘editedContactList’ : editedRecords
});
action.setCallback(this,function(response) {
var state = response.getState();
if (state === “SUCCESS”) {
//if update is successful
if(response.getReturnValue() === true){
helper.showToast({
“title”: “Record Update”,
“type”: “success”,
“message”: totalRecordEdited+” Contact Records Updated”
});
helper.reloadDataTable();
} else{ //if update got failed
helper.showToast({
“title”: “Error!!”,
“type”: “error”,
“message”: “Error in update”
});
}
}
});
$A.enqueueAction(action);
},

/*
* Show toast with provided params
* */
showToast : function(params){
var toastEvent = $A.get(“e.force:showToast”);
if(toastEvent){
toastEvent.setParams(params);
toastEvent.fire();
} else{
alert(params.message);
}
},

/*
* reload data table
* */
reloadDataTable : function(){
var refreshEvent = $A.get(“e.force:refreshView”);
if(refreshEvent){
refreshEvent.fire();
}
},
})

ContactDataTableController.apxc

public with sharing class ContactDataTableController {

@AuraEnabled
public static List<Contact> getContacts(Id accountId)
{
return [SELECT Id, Name, title, Email, Phone,Name_Range__c, Board_Contact__c FROM Contact WHERE AccountId =: accountId];
}

@AuraEnabled
public static boolean updateContacts(List<Contact> editedContactList){
try{
update editedContactList;
return true;
} catch(Exception e){
return false;
}
}
}