So I figured out a way to do this (hence adding it as an answer), but it feels very very ugly, and I'm sure I'm not using some basic Aura abilities.. so any improvements are more than welcome.
Here's the code:
Component markup:
<aura:component implements="forceCommunity:availableForAllPageTypes" access="global">
<div class="slds-tabs--default">
<ul class="slds-tabs--default__nav" role="tablist">
<li aura:id="tabpage" class="slds-tabs--default__item slds-text-heading--label slds-active" title="Active" onclick="{!c.changeTab}"
role="presentation"><a class="slds-tabs--default__link" href="javascript:void(0);" role="tab" tabindex="0" aria-selected="true" aria-controls="tab-default-1" id="tab-default-1__item">Active</a></li>
<li aura:id="tabpage" class="slds-tabs--default__item slds-text-heading--label" title="Previous" onclick="{!c.changeTab}"
role="presentation"><a class="slds-tabs--default__link" href="javascript:void(0);" role="tab" tabindex="-1" aria-selected="false" aria-controls="tab-default-2" id="tab-default-2__item">Previous</a></li>
</ul>
<div aura:id="tab-default-1" class="slds-tabs--default__content slds-show" role="tabpanel" aria-labelledby="tab-default-1__item">Item One Content</div>
<div aura:id="tab-default-2" class="slds-tabs--default__content slds-hide" role="tabpanel" aria-labelledby="tab-default-2__item">Item Two Content</div>
</div>
</aura:component>
Helper (used to find the div I clicked in):
({
getContainerDiv: function(event, element) {
var elem;
if (!element) {
elem = event.srcElement;
}
else {
elem = element;
}
if (elem.classList.contains('slds-tabs--default__item')) {
return elem;
}
else {
return this.getContainerDiv(event, elem.parentElement);
}
}
})
JS Controller (main logic):
({
changeTab: function(component, event, helper) {
var clickedTab = helper.getContainerDiv(event, null);
var tabs = component.find('tabpage');
for(idx = 0; idx < tabs.length; idx++)
{
tab = tabs[idx].elements[0];
$A.util.removeClass(tab, 'slds-active');
$A.util.removeClass(component.find(tab.children[0].getAttribute('aria-controls')), 'slds-show');
$A.util.addClass(component.find(tab.children[0].getAttribute('aria-controls')), 'slds-hide');
}
$A.util.addClass(clickedTab, 'slds-active');
$A.util.addClass(component.find(clickedTab.children[0].getAttribute('aria-controls')), 'slds-show');
$A.util.removeClass(component.find(clickedTab.children[0].getAttribute('aria-controls')), 'slds-hide');
}
})
If you are implementing this functionality for a client, please refer to my below comments.
When we are developing in Salesforce, there are couple of things we need to keep in mind. Salesforce platform provides point and click configurations which can be customised for our needs. Usually we try to avoid any coding if there is a possibility for a config only solution. There are few reasons behind this. 1) We don't need to maintain any config functionality. 2) Any updates/improvements provided by Salesforce get applied automatically. By looking at your requirement, this functionality can be easily implemented by adding the "Clone" action to the layout.
If you are trying to learn how to implement a lightning component with record data refer to below comments.
Whole point of implementing lightning record data is to avoid the server-side call back. So you do not need to implement your apex controller at all. Use force:recordData
to load and create your new record. Also note that you don't have to specify both layoutType
and fields
. If you want to define layoutType
make sure any fields you want to display is added to the layout as well.
So refactored component code should look like this.
<aura:attribute name="RecordSave" type="Target_Realization__c" />
<aura:attribute name="SimpleRecordSave" type="Target_Realization__c" />
<aura:attribute name="recordError" type="String"/>
<force:recordData aura:id="RecordReplicatorLoad"
recordId="{!v.recordId}"
targetFields="{!v.SimpleRecordLoad}"
targetRecord="{!v.RecordLoad}"
targetError="{!v.recordError}"
fields="Start_Date__c, End_Date__c, Target__c, Value__c, Value_Distribution_Type__c"
mode="EDIT"/>
<force:recordData aura:id="RecordReplicatorSave"
targetFields="{!v.SimpleRecordSave}"
targetRecord="{!v.RecordSave}"
targetError="{!v.recordError}"
fields="Start_Date__c, End_Date__c, Target__c, Value__c, Value_Distribution_Type__c"
mode="EDIT"/>
<div aura:id="editDialog" role="dialog" tabindex="-1" aria-labelledby="header43" class="slds-modal slds-fade-in-open">
<div class="slds-modal__container">
<div class="slds-modal__header">
<h2 class="slds-text-heading_medium">Clone Target Realization Record</h2>
</div>
<div class="slds-modal__content slds-p-around--medium slds-grid slds-wrap ">
<ui:inputDate aura:id="StartDate" label="Start Date" value="{!v.SimpleRecordLoad.Start_Date__c}" displayDatePicker="true"/>
<ui:inputDate aura:id="EndDate" label="End Date" value="{!v.SimpleRecordLoad.End_Date__c}" displayDatePicker="true"/>
<lightning:select aura:id="Value_Distribution_Type__c" name="Value_Distribution_Type__c" value="{!v.SimpleRecordLoad.Value_Distribution_Type__c}" required="true" label="Target Type" class="slds-size--1-of-2 slds-p-horizontal_x-small">
<option>Select Distribution Type</option>
<option value="Individual" >Individual</option>
<option value="Group">Group</option>
</lightning:select>
</div>
<div class="slds-modal__footer">
<lightning:button variant="neutral" label="Cancel" onclick="{!c.cancelDialog}"/>
<lightning:button variant="brand" label="Submit" onclick="{!c.saveAndCreateRecord}"/>
</div>
</div>
</div>
Then the controller:
({
saveAndCreateRecord : function(component, event, helper) {
// Prepare a new record from template
component.find("RecordReplicatorSave").getNewRecord(
"Target_Realization__c", // sObject type (objectApiName)
null, // recordTypeId
false, // skip cache?
$A.getCallback(function() {
var rec = component.get("v.RecordSave");
var error = component.get("v. recordError");
if(error || (rec === null)) {
console.log("Error initializing record template: " + error);
return;
}
console.log("Record template initialized: " + rec);
//map all clone fields
component.set("v.SimpleRecordSave.Start_Date__c", component.get("v.SimpleRecordLoad.Start_Date__c"));
component.set("v.SimpleRecordSave.End_Date__c", component.get("v.SimpleRecordLoad.End_Date__c"));
component.set("v.SimpleRecordSave.Value_Distribution_Type__c", component.get("v.SimpleRecordLoad.Value_Distribution_Type__c"));
component.find("RecordReplicatorSave").saveRecord(function(saveResult) {
if (saveResult.state === "SUCCESS" || saveResult.state === "DRAFT") {
// record is saved successfully
var resultsToast = $A.get("e.force:showToast");
resultsToast.setParams({
"title": "Saved",
"message": "The record was saved."
});
resultsToast.fire();
} else {
console.log(JSON.stringify(saveResult.error));
}
});
})
);
},
})
Note that I haven't complied or tested this code. So please be aware that there may be syntax issues. But by following this approach you should be able to get this working.
Best Answer
Yes, you can: