7

There are use cases, such as the expense tracker app in the Lightning Components Developer's Guide, where users are entering data into a dynamic list that grows with each user input submission. My question is, in these situations, what is the most efficient way to implement a UI element that allows the user to remove an item from the list?

enter image description here

8

Luckily the aura:iteration component has a super convenient, built-in attribute called indexVar. By leveraging indexVar I am able to pass the array index to the controller action, which can then use Array.prototype.splice() to remove an element from the list.

For example, consider the following aura:iteration element:

<aura:iteration items="{!v.leads}" var="lead" indexVar="i">
    <tr>
        <td>
            <ui:button label="Remove" press="{!c.handleRemoveLeadButtonClick}">
                <span data-index="{!i}"></span>
            </ui:button>
            <a href="#" data-index="{!i}" onclick="{!c.handleRemoveLeadAnchorClick}">
                Remove
            </a>
        </td>
        <td>{!lead.FirstName}</td>
        <td>{!lead.LastName}</td>
        <td>{!lead.Company}</td>
        <td>{!lead.Email}</td>
    </tr>
</aura:iteration>

I've intentionally included a ui:button and a standard HTML a (anchor) to show how to get the index value in both cases. The controller actions are shown below.

({
    handleRemoveLeadButtonClick : function(component, event, helper) {
        var self = this;  // safe reference

        var domEvent = event.getParams().domEvent;
        var bodySpan = domEvent.target.nextSibling;
        var index = bodySpan.dataset.index;
        helper.removeLead(component, index);
    },
    handleRemoveLeadAnchorClick : function(component, event, helper) {
        var self = this;  // safe reference

        var index = event.target.dataset.index;
        helper.removeLead(component, index);
    }
)}

And helper.removeLead() is defined as follows:

({
    removeLead : function(component, index) {
        var leads = component.get("v.leads");
        leads.splice(index, 1);
        component.set("v.leads", leads);
    }
})
  • What if I'm using a checkbox to remove an item? I'm neither using an anchor nor a button in my code. – Tyler Zika Aug 4 '16 at 1:26
1

I added a button in expenseList.cmp to handle removing of the expense item.

<ui:button label="Remove" press="{!c.remove}"/>

Then, I created an event, deleteExpenseItem.evt, to capture and pass the removed item.

<aura:event type="APPLICATION">
 <aura:attribute name="expense" type="Expense__c"/>
</aura:event>

Fire the event in expenseListController.js.

remove: function(component, evt, helper) {
    var expense = component.get("v.expense");    
    var deleteEvent = $A.get("e.c:deleteExpenseItem");
    deleteEvent.setParams({ "expense": expense }).fire();
}

Handle the event in form.cmp.

<aura:handler event="c:deleteExpenseItem" action="{!c.deleteEvent}" />

Add the handler to formController.js.

deleteEvent : function(component, event, helper) {
    helper.deleteExpense(component, event.getParam("expense"));
}

Call your Apex controller to delete the expense item and update the view in formHelper.js.

deleteExpense : function(component, expense, callback) {

    var action = component.get("c.deleteExpense");
    var self = this;
    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);
            self.updateTotal(component);
        }
    });
    $A.enqueueAction(action);
}

And don't forget to include the delete DML operation in ExpenseController.apxc.

@AuraEnabled
public static Expense__c deleteExpense(Expense__c expense) {
    delete expense;
    return expense;
}
  • This is incredible for such a simple operation. The effect is the same as if you accessed the element and called a .remove on it. Why wouldn't there be a .remove? I can dynamically create and add components why can't I also remove them in a very simple manner especially if I have a reference to the component I created dynamically in the first place. This is insane complexity for things that are so simple. – Scott Morrison Sep 29 '16 at 16:24

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.