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?
2 Answers
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. Commented Aug 4, 2016 at 1:26
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. Commented Sep 29, 2016 at 16:24