2

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>
1

It looks like you are missing just one (important) item.

You haven't declared your component event on the component markup. It should look similar to this:

<aura:registerEvent name="deleteExpenseItem" type="c:deleteExpenseItem"/>

Put this in the spendingItem component markup.

Also, while it's nice to see some code to help diagnose the problem, putting it ALL there makes it harder - it's a lot of code for people to read.

  • Yes, I know, that I should put this line in the spendingItem compoment, but when I put this, I have an error: [ERROR]: 0Ad0O000000a1ml:19,82: Invalid attribute "name": Source How can I solve that? – Natalia Dec 14 '17 at 21:29
  • So I put <aura:registerEvent name="deleteExpenseItem" type="c:deleteExpenseItem"/> in another place in spendingItem component and this error disappear, but another occured: Unknown controller action 'deleteExpense' Failing descriptor: {markup://c:spendingList} I dont have any idea, what to do with that – Natalia Dec 14 '17 at 21:43
  • Are you sure that your event is a COMPONENT event? try changing the name to something different from the name of the event (ie name="deleteExpense") – Caspar Harmer Dec 14 '17 at 22:37
  • If you get totally stuck, change it to an application event. – Caspar Harmer Dec 14 '17 at 22:39
  • I changed to application event and changed the name of the event and it still does not work... Action failed: c:spendingItem$controller$delete [deleteEvent is null]. Could you tell me, which one is the container component, and which one is sub-component according to developer.salesforce.com/docs/atlas.en-us.lightning.meta/… ? – Natalia Dec 14 '17 at 23:20

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.