I'm trying to create remove item functionality using this How to remove items from a dynamic list in Lightning component? and this tutorial https://developer.salesforce.com/docs/atlas.en-us.lightning.meta/lightning/apex_records_delete.htm hovewer removing still does not work...
My components:
expenses.cmp
<aura:component controller="ExpensesController" implements="force:appHostable,flexipage:availableForAllPageTypes">
<aura:attribute name="expenses" type="Expense__c[]"/>
<aura:attribute name="newExpense" type="Expense__c"
default="{ 'sobjectType': 'Expense__c',
'Name': '',
'Amount__c': 0,
'Spending__c': 0,
'CreatedAt__c': '' }"/>
<aura:handler name="init" action="{!c.doInit}" value="{!this}"/>
<!-- PAGE HEADER -->
<lightning:layout class="slds-page-header slds-page-header--object-home">
<lightning:layoutItem>
<lightning:icon iconName="custom:custom17" alternativeText="My Spendings"/>
</lightning:layoutItem>
<lightning:layoutItem padding="horizontal-small">
<div class="page-section page-header">
<h1 class="slds-text-heading--label">Donkey Money</h1>
<h2 class="slds-text-heading--medium">Service, that helps you manage your spendings.</h2>
</div>
</lightning:layoutItem>
</lightning:layout>
<!-- / PAGE HEADER -->
<!-- NEW EXPENSE FORM -->
<lightning:layout>
<lightning:layoutItem padding="around-small" size="6">
<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 incomings and spendings
</legend>
<!-- CREATE NEW EXPENSE FORM -->
<form class="slds-form--stacked">
<lightning:input aura:id="expenseform" label="Name"
name="expensename"
value="{!v.newExpense.Name}"
required="true"/>
<lightning:input type="number" aura:id="expenseform" label="Incomings"
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 type="number" aura:id="expenseform" label="Spending"
name="expenseamount"
min="0.1"
formatter="currency"
step="0.01"
value="{!v.newExpense.Spending__c}"
messageWhenRangeUnderflow="Enter an amount that's at least $0.10."/>
<lightning:input type="date" aura:id="expenseform" label="Created at"
name="expensedate"
value="{!v.newExpense.CreatedAt__c}"/>
<lightning:button label="Create"
class="slds-m-top--medium"
variant="brand"
onclick="{!c.clickCreate}"/>
</form>
<!-- / CREATE NEW EXPENSE FORM -->
</fieldset>
<!-- / BOXED AREA -->
</div>
</lightning:layoutItem>
<lightning:layoutItem padding="around-small" size="6">
<c:spendingList expenses="{!v.expenses}"/>
</lightning:layoutItem>
</lightning:layout>
<!-- / NEW EXPENSE FORM -->
expensesController.js
({
// Load expenses from Salesforce
doInit: function(component, event, helper) {
var mydate = component.get("v.expense.CreatedAt__c");
if(mydate){
component.set("v.formatdate", new Date(mydate));
}
// Create the action
var action = component.get("c.getExpenses");
// Add callback behavior for when response is received
action.setCallback(this, function(response) {
var 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);
},
clickCreate: function(component, event, helper) {
var 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
var newExpense = component.get("v.newExpense");
console.log("Create expense: " + JSON.stringify(newExpense));
helper.createExpense(component, newExpense);
}
}
})
expensesHelper.js
({
createExpense: function(component, expense) {
var action = component.get("c.saveExpense");
action.setParams({
"expense": expense
});
action.setCallback(this, function(response){
var state = response.getState();
if (state === "SUCCESS") {
var expenses = component.get("v.expenses");
expenses.push(response.getReturnValue());
component.set("v.expenses", expenses);
}
});
$A.enqueueAction(action);
}
})
spendingList.cmp
<aura:component>
<aura:attribute name="expenses" type="Expense__c[]"/>
<aura:handler name="deleteExpenseItem" event="c:deleteExpenseItem" action="{!c.deleteEvent}" />
<lightning:layout>
<lightning:layoutItem padding="around-small" size="12">
<lightning:card title="Spendings">
<p class="slds-p-horizontal--small">
<aura:iteration items="{!v.expenses}" var="expense">
<c:spendingItem expense="{!expense}"/> <!--c:spendingItem is the sub-component -->
</aura:iteration>
</p>
</lightning:card>
</lightning:layoutItem>
</lightning:layout>
</aura:component>
spendingListController.js
({
deleteEvent : function(component, event, helper) {
helper.deleteExpense(component, event.getParam("expense"));
}
})
spendingListHelper.js
({
deleteExpense : function(component, expense, callback) {
// Call the Apex controller and update the view in the callback
var action = component.get("c.deleteExpense");
action.setParams({
"expense": expense
});
action.setCallback(this, function(response) {
var state = response.getState();
if (state === "SUCCESS") {
// Remove only the deleted expense from view
var expenses = component.get("v.expenses");
var items = [];
for (i = 0; i < expenses.length; i++) {
if(expenses[i]!==expense) {
items.push(expenses[i]);
}
}
component.set("v.expenses", items);
}
});
$A.enqueueAction(action);
}
})
spendingItem.cmp
<aura:component>
<aura:registerEvent name="deleteExpense" type="c:deleteExpenseItem"/>
<aura:handler name="init" value="{!this}" action="{!c.doInit}"/>
<aura:attribute name="formatdate" type="Date"/>
<aura:attribute name="expense" type="Expense__c"/>
<lightning:card title="{!v.expense.Name}" iconName="standard:quotes">
<aura:set attribute="footer">
<p>Date: <lightning:formattedDateTime value="{!v.formatdate}"/></p>
<p class="slds-text-title"><lightning:relativeDateTime value="{!v.formatdate}"/></p>
</aura:set>
<p class="slds-text-heading--medium slds-p-horizontal--small">
Incomings: <lightning:formattedNumber value="{!v.expense.Amount__c}" style="currency"/>
</p>
<p class="slds-text-heading--medium slds-p-horizontal--small">
Spending: <lightning:formattedNumber value="{!v.expense.Spending__c}" style="currency"/>
</p>
<lightning:button label="Delete" onclick="{!c.delete}"/>
</lightning:card>
spendingItemController.js
({
doInit : function(component, event, helper) {
var mydate = component.get("v.expense.CreatedAt__c");
if(mydate){
component.set("v.formatdate", new Date(mydate));
}
},
delete : function(component, evt, helper) {
var expense = component.get("v.expense");
var deleteEvent = component.getEvent("deleteExpenseItem");
console.log(expense)
deleteEvent.setParams({ "expense": expense }).fire();
}
})
When I try to remove, I have the following error:
This page has an error. You might just need to refresh it. Action failed: c:spendingItem$controller$delete [deleteEvent is null] Failing descriptor: {c:spendingItem$controller$delete}
console.log(expense)
in spendingItemController shows single (correct) object
Object { Id: "a020O00001M04xKQAR", Name: "gdfgn", Amount__c: 34, Spending__c: 90, CreatedAt__c: "2017-12-04", CreatedDate: "2017-12-13T15:48:41.000Z" }
deleteExpense.cls
public with sharing class deleteExpense {
@AuraEnabled
public static Expense__c deleteExpense(Expense__c expense) {
// Perform isDeletable() check here
delete expense;
return expense;
}}
deleteExpenseItem.evt
<aura:event type="COMPONENT">
<aura:attribute name="expense" type="Expense__c"/></aura:event>