function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
SeanCenoSeanCeno 

Delete button only deleting top row?

My delete button seems to only be deleting the top row, not the specified row. A {!rowNumber+1} deletes the 2nd row each time, then hits an out of bounds error, naturally. Can anybody see what I'm doing wrong?
 
public void addRow(){
        expenseLineItemAllocationList.add(new Expense_Line_Item_Allocation__c());
    }
    
    public void saveCompany(){
        for(Expense_Line_Item_Allocation__c ela: expenseLineItemAllocationList) ela.Expense_Line_Item_Detail__c = expenseLineItem.Id;
        upsert expenseLineItemAllocationList;
    }
    
    public integer rowIndex {get; set;}
    public Expense_Line_Item_Allocation__c del;
    public void deleteRow(){
        //System.debug('row to be deleted ' + rowIndex );
        //System.debug('row item to be deleted '+expenseLineItemAllocationList[rowIndex]);
        del = new Expense_Line_Item_Allocation__c();
        del = expenseLineItemAllocationList.remove(rowIndex);
    }
 
<apex:pageBlockSection id="Allocation" title="Allocate Expenses" Columns="1"  collapsible="false" rendered="{!(expenseLineItem.AllocationCheckbox__c == true)}">
                <apex:outputLabel value="Please select the Managed Company and the percentage amount you wish to allocate to it. Press Save in order to see the Allocation Split value." />
                <apex:variable var="rowNumber" value="{!0}"/>
                <apex:pageBlockTable id="allocationTable" var="allocation" columns="4" value="{!expenseLineItemAllocationList}">
                    <apex:column headerValue="Managed Company">
                        <apex:inputField value="{!allocation.Product__c}"/>
                    </apex:column>
                    <apex:column headerValue="Allocation %">
                        <apex:inputField value="{!allocation.Allocation__c}"/>
                    </apex:column>
                    <apex:column headerValue="Allocation Split">
                        <apex:outputField value="{!allocation.Allocation_Split__c}"/>
                    </apex:column>
                    <apex:column headerValue="Action">
                        <apex:commandButton value="Delete" action="{!deleteRow}" rerender="Allocation">
                            <apex:param name="Allocation" value="{!rowNumber}" assignTo="{!rowIndex}"/>
                        </apex:commandButton>
                    </apex:column>
                    <apex:variable var="rowNumber" value="{!rowNumber}" />
                </apex:pageBlockTable>
                <apex:commandButton value="Add Row" action="{!addRow}" rerender="allocationTable"/>
            </apex:pageBlockSection>

 
Best Answer chosen by SeanCeno
mjohnson-TICmjohnson-TIC
Final attempt haha. This is code I usually use for deleting a single row on an action event. Keep the Visualforce page the same as I showed above with the new deleteId param.
 
public void saveCompany(){
        for(Expense_Line_Item_Allocation__c ela: expenseLineItemAllocationList){ 
	        ela.Expense_Line_Item_Detail__c = expenseLineItem.Id;
	       	upsert ela;
        }
    }
    
    public integer rowIndex {get; set;}
    public Expense_Line_Item_Allocation__c del;
    public string deleteId {get;set;}
    public void deleteRow(){
        //System.debug('row to be deleted ' + rowIndex );
        //System.debug('row item to be deleted '+expenseLineItemAllocationList[rowIndex]);
        del = new Expense_Line_Item_Allocation__c();
        del = expenseLineItemAllocationList.remove(rowIndex);
        if(deleteId != null){
	        try{
	        	Expense_Line_Item_Allocation__c elia = new Expense_Line_Item_Allocation__c(id=deleteId);
	        	delete elia;
	        }catch(exception e){
	        	system.debug(string.value0f(e));//unable to be deleted
	        }
        }
    }



 

All Answers

AshlekhAshlekh
Hi 

Hope below code will helps you
public void deleteRow()
{
	del = new Expense_Line_Item_Allocation__c();
	// Below line will give error because expenseLineItemAllocationList will return a list. 
	//del = expenseLineItemAllocationList.remove(rowIndex);

	IF(rowIndex != null && expenseLineItemAllocationList!=null && expenseLineItemAllocationList.size()>=rowIndex)
			expenseLineItemAllocationList.remove(rowIndex);

}

Mark it as a solution if it helps you
 
SeanCenoSeanCeno
Hey Ashlekh,

Thanks for the respone. The code compiles, but it's still deleting the only the top row first. Do I need to change my variable in my VF page to {!del}?
mjohnson-TICmjohnson-TIC
try this
 
<apex:pageBlockSection id="Allocation" title="Allocate Expenses" Columns="1"  collapsible="false" rendered="{!(expenseLineItem.AllocationCheckbox__c == true)}">
                <apex:outputLabel value="Please select the Managed Company and the percentage amount you wish to allocate to it. Press Save in order to see the Allocation Split value." />
                <apex:variable var="rowNumber" value="{!0}"/>
                <apex:pageBlockTable id="allocationTable" var="allocation" columns="4" value="{!expenseLineItemAllocationList}">
                    <apex:column headerValue="Managed Company">
                        <apex:inputField value="{!allocation.Product__c}"/>
                    </apex:column>
                    <apex:column headerValue="Allocation %">
                        <apex:inputField value="{!allocation.Allocation__c}"/>
                    </apex:column>
                    <apex:column headerValue="Allocation Split">
                        <apex:outputField value="{!allocation.Allocation_Split__c}"/>
                    </apex:column>
                    <apex:column headerValue="Action">
                        <apex:commandButton value="Delete" action="{!deleteRow}" rerender="Allocation">
                            <apex:param name="Allocation" value="{!FLOOR(rowNumber)}" assignTo="{!rowIndex}"/>
                        </apex:commandButton>
                    </apex:column>
                    <apex:variable var="rowNumber" value="{!rowNumber+1}" />
                </apex:pageBlockTable>
                <apex:commandButton value="Add Row" action="{!addRow}" rerender="allocationTable"/>
            </apex:pageBlockSection>

 
SeanCenoSeanCeno
Hey mjohnson-TIC ,

Thanks for the response. Still the same result. Does the fact that the number of rows initially created comes from a multi-select picklist? Here's the logic in the getter for that:
 
//New Object For Custom Allocation
    public Expense_Line_Item_Allocation__c expenseLineItemAllocation {get; set;} //insert field from allocation
    public List<Expense_Line_Item_Allocation__c> expenseLineItemAllocationList {get {
        if (ExpenseLineItemAllocationList != null)
            return ExpenseLineItemAllocationList;
        if (controller.getId() != null) try {
            ExpenseLineItemAllocationList = [
                select Allocation__c
                , Product__c
                , Expense_Split_Amount__c
                , Expense_Line_Item_Detail__c
                , Share_Of_Total_Allocation__c
                , Allocation_Split__c
                
                from Expense_Line_Item_Allocation__c
                where Expense_Line_Item_Detail__c = :expenseLineItem.Id
                order by Product__c desc
            ];
            
        } catch (System.DmlException dmlException) {
            ApexPages.addMessages(dmlException);
        }
        if (ExpenseLineItemAllocationList == null || ExpenseLineItemAllocationList.size() == 0) {
            ExpenseLineItemAllocationList = new List<Expense_Line_Item_Allocation__c>();
            if(expenseLineItem != null && !String.isBlank(expenseLineItem.Managed_Company__c)) {
                string[] parsedCompanies = expenseLineItem.Managed_Company__c.split(';');
                for(string s: parsedCompanies) {
                    ExpenseLineItemAllocationList.add(new Expense_Line_Item_Allocation__c(product__c = s));
                }
            }
        }
        return ExpenseLineItemAllocationList;
    } set;} //insert list of fields in allocation
Basically if the user selects to do a custom allocation after selecting the companies, a new section drops down with the first field (picklists with the same values as multi-select) populated with the multi-select options. Then the user can choose the percentage to multiply it by. I want these rows to be editable though. Add row works fine, but delete not so much.
 
mjohnson-TICmjohnson-TIC
Sorry, the apex variable that adds +1 needs to be within the apex:column, otherwise it won't add 1. Try this.
 
<apex:pageBlockSection id="Allocation" title="Allocate Expenses" Columns="1"  collapsible="false" rendered="{!(expenseLineItem.AllocationCheckbox__c == true)}">
                <apex:outputLabel value="Please select the Managed Company and the percentage amount you wish to allocate to it. Press Save in order to see the Allocation Split value." />
                <apex:variable var="rowNumber" value="{!0}"/>
                <apex:pageBlockTable id="allocationTable" var="allocation" columns="4" value="{!expenseLineItemAllocationList}">
                    <apex:column headerValue="Managed Company">
                        <apex:inputField value="{!allocation.Product__c}"/>
                    </apex:column>
                    <apex:column headerValue="Allocation %">
                        <apex:inputField value="{!allocation.Allocation__c}"/>
                    </apex:column>
                    <apex:column headerValue="Allocation Split">
                        <apex:outputField value="{!allocation.Allocation_Split__c}"/>
                    </apex:column>
                    <apex:column headerValue="Action">
                        <apex:commandButton value="Delete" action="{!deleteRow}" rerender="Allocation">
                            <apex:param name="Allocation" value="{!FLOOR(rowNumber)}" assignTo="{!rowIndex}"/>
                        </apex:commandButton>
<apex:variable var="rowNumber" value="{!rowNumber+1}" />
                    </apex:column>                  
                </apex:pageBlockTable>
                <apex:commandButton value="Add Row" action="{!addRow}" rerender="allocationTable"/>
            </apex:pageBlockSection>

 
SeanCenoSeanCeno
Totally works now! Thanks! I have one last question..The saveCompany() method doesn't seem to update once I edit / delete a row. This method is connected to a Save button. Do you see anything wrong with it?
 
public void saveCompany(){
        for(Expense_Line_Item_Allocation__c ela: expenseLineItemAllocationList) ela.Expense_Line_Item_Detail__c = expenseLineItem.Id;
        upsert expenseLineItemAllocationList;
    }

 
mjohnson-TICmjohnson-TIC
 
public void saveCompany(){
        for(Expense_Line_Item_Allocation__c ela: expenseLineItemAllocationList){ 
	        ela.Expense_Line_Item_Detail__c = expenseLineItem.Id;
	       	upsert ela;
        }
    }


 
SeanCenoSeanCeno
Hmm still refreshes back to the first save values...
mjohnson-TICmjohnson-TIC

may have to take a look at the debug log when clicking save

 

public void saveCompany(){
        system.debug('List Size: '+expenseLineItemAllocationList.size);
        for(Expense_Line_Item_Allocation__c ela: expenseLineItemAllocationList){ 
	        ela.Expense_Line_Item_Detail__c = expenseLineItem.Id;
	       	try{
	       		upsert ela;
	       		system.debug('Update Success: '+ela.Id);
	       	}catch(exception e){
	       		system.debug('Error: '+string.valueof(e));
	       	}
        }
    }
SeanCenoSeanCeno
The debug log isn't returning any debugs with the "Debug Only" check box. Very strange that the record isn't updating when deleting a row, but it'll save the AddRow if I add a row...

Here is the code for a Save and New button. As you can see the saveCompany() method is in there:
public PageReference upsertLineItemAndNew() {
        upsertLineItem();
        saveCompany();
        system.debug(expenseLineItemAllocationList);
        
        if (ApexPages.hasMessages(ApexPages.Severity.Error))
            return null;
        
        return createLineItem();
    }

 
mjohnson-TICmjohnson-TIC
The removerow method needs to delete the record if it is already inserted with an Id. You probably need to create a new list<Expense_Line_Item_Allocation__c> for deleteids and delete them in the save method. Something like this should work.
 
public void addRow(){
        expenseLineItemAllocationList.add(new Expense_Line_Item_Allocation__c());
    }
    
public void saveCompany(){
        for(Expense_Line_Item_Allocation__c ela: expenseLineItemAllocationList){ 
	        ela.Expense_Line_Item_Detail__c = expenseLineItem.Id;
	       	upsert ela;
        }
        if(deleteItems != null){
        	delete deleteItems;
        	deleteItems.clear();
        }
    }
    
    public integer rowIndex {get; set;}
    public Expense_Line_Item_Allocation__c del;
    public list<Expense_Line_Item_Allocation__c> deleteItems {get;set;}
    public void deleteRow(){
        //System.debug('row to be deleted ' + rowIndex );
        //System.debug('row item to be deleted '+expenseLineItemAllocationList[rowIndex]);
        del = new Expense_Line_Item_Allocation__c();
        del = expenseLineItemAllocationList.remove(rowIndex);
        if(expenseLineItemAllocationList[rowIndex].Id != null){
        	deleteItems.add(expenseLineItemAllocationList[rowIndex]);
        }
    }



 
SeanCenoSeanCeno
Getting either a List index out of bounds: 3 error at line 24 or Attempt to dereference a null object error at 25. I assume I need to change the VF page to not +1? Or remove the Floor?
mjohnson-TICmjohnson-TIC

Oops, was was removing the row before adding the delete Id.

public void deleteRow(){
        //System.debug('row to be deleted ' + rowIndex );
        //System.debug('row item to be deleted '+expenseLineItemAllocationList[rowIndex]);
        del = new Expense_Line_Item_Allocation__c();
        if(expenseLineItemAllocationList[rowIndex].Id != null){
        	deleteItems.add(expenseLineItemAllocationList[rowIndex]);
        }
        del = expenseLineItemAllocationList.remove(rowIndex);
    }
SeanCenoSeanCeno
Sorry I'm having such a tough time! Still having a null pointer error here
 deleteItems.add(expenseLineItemAllocationList[rowIndex]);

Do I need to instantiate deleteItems somewhere?
14:10:26:164 CODE_UNIT_ST… [EXTERNAL]|ExpenseReport set(rowIndex,4)
14:10:26:164 SYSTEM_MODE… true
14:10:26:164 CODE_UNIT_ST… [EXTERNAL]|ExpenseReport set(rowIndex,4)
14:10:26:164 CODE_UNIT_FI… ExpenseReport set(rowIndex,4)
14:10:26:164 CODE_UNIT_FI… ExpenseReport set(rowIndex,4)
14:10:26:165 CODE_UNIT_ST… [EXTERNAL]|01pA0000001DSlx|ExpenseReport invoke(deleteRow)
14:10:26:165 SYSTEM_MODE… false
14:10:26:165 SYSTEM_METH… [853]|ExpenseReport.__sfdc_expenseLineItemAllocationList()
14:10:26:165 SYSTEM_METH… [853]|ExpenseReport.__sfdc_expenseLineItemAllocationList()
14:10:26:165 SYSTEM_METH… [853]|ExpenseReport.__sfdc_rowIndex()
14:10:26:165 SYSTEM_METH… [853]|ExpenseReport.__sfdc_rowIndex()
14:10:26:165 SYSTEM_METH… [854]|ExpenseReport.__sfdc_deleteItems()
14:10:26:165 SYSTEM_METH… [854]|ExpenseReport.__sfdc_deleteItems()
14:10:26:165 SYSTEM_METH… [854]|ExpenseReport.__sfdc_expenseLineItemAllocationList()
14:10:26:165 SYSTEM_METH… [854]|ExpenseReport.__sfdc_expenseLineItemAllocationList()
14:10:26:165 SYSTEM_METH… [854]|ExpenseReport.__sfdc_rowIndex()
14:10:26:165 SYSTEM_METH… [854]|ExpenseReport.__sfdc_rowIndex()
14:10:26:165 SYSTEM_MODE… false
14:10:26:166 FATAL_ERROR System.NullPointerException: Attempt to de­reference a null object
14:10:26:000 FATAL_ERROR
14:10:26:000 FATAL_ERROR Class.ExpenseReport.deleteRow: line 854, column 1
14:10:26:166 CODE_UNIT_FI… ExpenseReport invoke(deleteRow)

 
mjohnson-TICmjohnson-TIC

hmm maybe you need to evaluate if the list index is not null first.. 

public void deleteRow(){
        //System.debug('row to be deleted ' + rowIndex );
        //System.debug('row item to be deleted '+expenseLineItemAllocationList[rowIndex]);
        if(expenseLineItemAllocationList[rowIndex] != null){
	        if(expenseLineItemAllocationList[rowIndex].Id != null){
	        	deleteItems.add(expenseLineItemAllocationList[rowIndex]);
	        }
        }
        del = new Expense_Line_Item_Allocation__c();
        del = expenseLineItemAllocationList.remove(rowIndex);
    }
SeanCenoSeanCeno
Yeah it really doesn't seem to like the deleteItems.add(expenseLineItemAllocationList[rowIndex]);
mjohnson-TICmjohnson-TIC
Mybe if you changed deleteItems to a list of <Id> and added expenseLineItemAllocationList[rowIndex].Id to the list to be deleted.
SeanCenoSeanCeno
Sorry what do you mean?
mjohnson-TICmjohnson-TIC
public void addRow(){
        expenseLineItemAllocationList.add(new Expense_Line_Item_Allocation__c());
    }
    
public void saveCompany(){
        for(Expense_Line_Item_Allocation__c ela: expenseLineItemAllocationList){ 
	        ela.Expense_Line_Item_Detail__c = expenseLineItem.Id;
	       	upsert ela;
        }
        if(deleteItems != null){
        	delete deleteItems;
        	deleteItems.clear();
        }
    }
    
    public integer rowIndex {get; set;}
    public Expense_Line_Item_Allocation__c del;
    public list<Id> deleteItems {get;set;}
    public void deleteRow(){
        //System.debug('row to be deleted ' + rowIndex );
        //System.debug('row item to be deleted '+expenseLineItemAllocationList[rowIndex]);
        if(expenseLineItemAllocationList[rowIndex] != null){
	        if(expenseLineItemAllocationList[rowIndex].Id != null){
	        	deleteItems.add(expenseLineItemAllocationList[rowIndex].Id);
	        }
        }
        del = new Expense_Line_Item_Allocation__c();
        del = expenseLineItemAllocationList.remove(rowIndex);
    }
SeanCenoSeanCeno
Error here:

delete deleteItems;

DML requires SObject or SObject list type: List <id>
 
mjohnson-TICmjohnson-TIC
Try switching the save method with
 
public void saveCompany(){
        for(Expense_Line_Item_Allocation__c ela: expenseLineItemAllocationList){ 
	        ela.Expense_Line_Item_Detail__c = expenseLineItem.Id;
	       	upsert ela;
        }
        if(deleteItems != null){
        	for(Expense_Line_Item_Allocation__c e: [Select Id from Expense_Line_Item_Allocation__c where Id in: delteItems]){
        		delete e;
        	}
        }
    }

 
SeanCenoSeanCeno
Yeah still the same error with the  deleteItems.add(expenseLineItemAllocationList[rowIndex].Id);

Not sure why it's throwing the error.

Attempt to de-reference a null object
Error is in expression '{!deleteRow}' in component <apex:commandButton> in page expensereport: Class.ExpenseReport.deleteRow: line 854, column 1
 
mjohnson-TICmjohnson-TIC
May have to do it this way then.. 
 
<apex:pageBlockSection id="Allocation" title="Allocate Expenses" Columns="1"  collapsible="false" rendered="{!(expenseLineItem.AllocationCheckbox__c == true)}">
                <apex:outputLabel value="Please select the Managed Company and the percentage amount you wish to allocate to it. Press Save in order to see the Allocation Split value." />
                <apex:variable var="rowNumber" value="{!0}"/>
                <apex:pageBlockTable id="allocationTable" var="allocation" columns="4" value="{!expenseLineItemAllocationList}">
                    <apex:column headerValue="Managed Company">
                        <apex:inputField value="{!allocation.Product__c}"/>
                    </apex:column>
                    <apex:column headerValue="Allocation %">
                        <apex:inputField value="{!allocation.Allocation__c}"/>
                    </apex:column>
                    <apex:column headerValue="Allocation Split">
                        <apex:outputField value="{!allocation.Allocation_Split__c}"/>
                    </apex:column>
                    <apex:column headerValue="Action">
                        <apex:commandButton value="Delete" action="{!deleteRow}" rerender="Allocation">
                            <apex:param name="Allocation" value="{!FLOOR(rowNumber)}" assignTo="{!rowIndex}"/>
<apex:param name="deleteId" value="{!allocation.Id}" assignTo="{!deleteId}"/>
                        </apex:commandButton>
<apex:variable var="rowNumber" value="{!rowNumber+1}" />
                    </apex:column>                  
                </apex:pageBlockTable>
                <apex:commandButton value="Add Row" action="{!addRow}" rerender="allocationTable"/>
            </apex:pageBlockSection>
 
public void saveCompany(){
        for(Expense_Line_Item_Allocation__c ela: expenseLineItemAllocationList){ 
	        ela.Expense_Line_Item_Detail__c = expenseLineItem.Id;
	       	upsert ela;
        }
        if(deleteItems != null){
        	for(Expense_Line_Item_Allocation__c e: [Select Id from Expense_Line_Item_Allocation__c where Id in: delteItems]){
        		delete e;
        	}
        }
    }
    
    public integer rowIndex {get; set;}
    public Expense_Line_Item_Allocation__c del;
    public string deleteId {get;set;}
    public list<Id> deleteItems {get;set;}
    public void deleteRow(){
        //System.debug('row to be deleted ' + rowIndex );
        //System.debug('row item to be deleted '+expenseLineItemAllocationList[rowIndex]);
	    deleteItems.add(deleteId);
        del = new Expense_Line_Item_Allocation__c();
        del = expenseLineItemAllocationList.remove(rowIndex);
    }

 
SeanCenoSeanCeno
Variable does not exist: deleteId??
mjohnson-TICmjohnson-TIC
Did you make sure to compile the class first so that "public string deleteId {get;set;}" is usable?
SeanCenoSeanCeno
Sorry missed that String definition. Another Attempt to de-reference a null object.
mjohnson-TICmjohnson-TIC
public void deleteRow(){
        //System.debug('row to be deleted ' + rowIndex );
        //System.debug('row item to be deleted '+expenseLineItemAllocationList[rowIndex]);
       if(deleteid != null){
	    deleteItems.add(deleteId);
       }
        del = new Expense_Line_Item_Allocation__c();
        del = expenseLineItemAllocationList.remove(rowIndex);
    }
SeanCenoSeanCeno
Same error. This is what the page looks like, not sure if it helps though.
User-added image
mjohnson-TICmjohnson-TIC
Final attempt haha. This is code I usually use for deleting a single row on an action event. Keep the Visualforce page the same as I showed above with the new deleteId param.
 
public void saveCompany(){
        for(Expense_Line_Item_Allocation__c ela: expenseLineItemAllocationList){ 
	        ela.Expense_Line_Item_Detail__c = expenseLineItem.Id;
	       	upsert ela;
        }
    }
    
    public integer rowIndex {get; set;}
    public Expense_Line_Item_Allocation__c del;
    public string deleteId {get;set;}
    public void deleteRow(){
        //System.debug('row to be deleted ' + rowIndex );
        //System.debug('row item to be deleted '+expenseLineItemAllocationList[rowIndex]);
        del = new Expense_Line_Item_Allocation__c();
        del = expenseLineItemAllocationList.remove(rowIndex);
        if(deleteId != null){
	        try{
	        	Expense_Line_Item_Allocation__c elia = new Expense_Line_Item_Allocation__c(id=deleteId);
	        	delete elia;
	        }catch(exception e){
	        	system.debug(string.value0f(e));//unable to be deleted
	        }
        }
    }



 
This was selected as the best answer
mjohnson-TICmjohnson-TIC
Oops, just noticed string.valueof is using a zero instead of O - need to fix that on line 21.
SeanCenoSeanCeno
You, my friend, are a god amongst men! Saving, adding, deleting, and rerendering as should. Thank you so much!