I'm working through the Aura Components Basics trailhead modules and am struggling a bit to get the example expenses.cmp component working correctly. This is code that I have taken straight from the module examples and modified while working through the instructions and tutorials.
What the code should do is:
- display a form that allows entry of Expense records
- display a list of existing expense records
What is actually occurring:
- displays a form that allows entry of Expense records. When the user enters data and clicks Create Expense, the newly submitted record shows in the Expenses list on teh Aura page but is not saved to the Salesforce org
- after refreshing the page, the expense records list only shows 2 expense records that I entered through the regular Salesforce UI, and anything entered by the user through this page is gone
What am I missing?
expenses.cmp component
<aura:attribute name="expenses" type="Expense__c[]"/>
<!--not sure if this should go after the first attribute or the second one-->
<aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
<aura:attribute name="newExpense" type="Expense__c"
default="{ 'sobjectType': 'Expense__c',
'Name': '',
'Amount__c': 0,
'Client__c': '',
'Date__c': '',
'Reimbursed__c': false }"/>
<!-- PAGE HEADER -->
<lightning:layout class="slds-page-header slds-page-header_object-home">
<lightning:layoutItem>
<lightning:icon iconName="standard:scan_card" alternativeText="My Expenses"/>
</lightning:layoutItem>
<lightning:layoutItem padding="horizontal-small">
<div class="page-section page-header">
<h1 class="slds-text-heading_label">Expenses</h1>
<h2 class="slds-text-heading_medium">My Expenses</h2>
</div>
</lightning:layoutItem>
</lightning:layout>
<!-- / PAGE HEADER -->
<!-- NEW EXPENSE FORM -->
<lightning:layout>
<lightning:layoutItem padding="around-small" size="6">
<!-- CREATE NEW EXPENSE -->
<div aria-labelledby="newexpenseform">
<!-- BOXED AREA -->
<fieldset class="slds-box slds-theme_default slds-container_small">
<legend id="newexpenseform" class="slds-text-heading_small
slds-p-vertical_medium">
Add Expense
</legend>
<!-- CREATE NEW EXPENSE FORM -->
<form class="slds-form_stacked">
<lightning:input aura:id="expenseform" label="Expense Name"
name="expensename"
value="{!v.newExpense.Name}"
required="true"/>
<lightning:input type="number" aura:id="expenseform" label="Amount"
name="expenseamount"
min="0.1"
formatter="currency"
step="0.01"
value="{!v.newExpense.Amount__c}"
messageWhenRangeUnderflow="Enter an amount that's at least $0.10."/>
<lightning:input aura:id="expenseform" label="Client"
name="expenseclient"
value="{!v.newExpense.Client__c}"
placeholder="ABC Co."/>
<lightning:input type="date" aura:id="expenseform" label="Expense Date"
name="expensedate"
value="{!v.newExpense.Date__c}"/>
<lightning:input type="checkbox" aura:id="expenseform" label="Reimbursed?"
name="expreimbursed"
checked="{!v.newExpense.Reimbursed__c}"/>
<lightning:button label="Create Expense"
class="slds-m-top_medium"
variant="brand"
onclick="{!c.clickCreate}"/>
</form>
<!-- / CREATE NEW EXPENSE FORM -->
</fieldset>
<!-- / BOXED AREA -->
</div>
<!-- / CREATE NEW EXPENSE -->
</lightning:layoutItem>
</lightning:layout>
<!-- / NEW EXPENSE FORM -->
<c:expensesList expenses="{!v.expenses}"/>
</aura:component>
expensesController.js
clickCreate: function(component, event, helper) {
let validExpense = component.find('expenseform').reduce(function (validSoFar, inputCmp) {
// Displays error messages for invalid fields
inputCmp.showHelpMessageIfInvalid();
return validSoFar && inputCmp.get('v.validity').valid;
}, true);
// If we pass error checking, do some real work
if(validExpense){
// Create the new expense
let newExpense = component.get("v.newExpense");
console.log("Create expense: " + JSON.stringify(newExpense));
helper.createExpense(component, newExpense);
}
},
// Load expenses from Salesforce
doInit: function(component, event, helper) {
// Create the action
let action = component.get("c.getExpenses");
// Add callback behavior for when response is received
action.setCallback(this, function(response) {
let state = response.getState();
if (state === "SUCCESS") {
component.set("v.expenses", response.getReturnValue());
}
else {
console.log("Failed with state: " + state);
}
});
// Send action off to be executed
$A.enqueueAction(action);
},
})
expensesHelper.js
createExpense: function(component, expense) {
//let theExpenses = component.get("v.expense");
let theExpenses = component.get("v.expenses");
// Copy the expense to a new object
// THIS IS A DISGUSTING, TEMPORARY HACK
let newExpense = JSON.parse(JSON.stringify(expense));
console.log("Expenses before 'create': " + JSON.stringify(theExpenses));
theExpenses.push(newExpense);
component.set("v.expenses", theExpenses);
//component.set("v.expense", theExpenses);
console.log("Expenses after 'create': " + JSON.stringify(theExpenses));
console.log("Expenses in newExpense variable: " + JSON.stringify(newExpense));
}
})