9

I created a visualforce page (with controller) that allows adding multiple records to a custom object (master object is account). I can add new rows and save the new records, I'm also pulling information from the master records. What I'm missing is the ability to remove each row separately - a custom button or a link. Can someone assist me with this?

Visualforce:

<apex:page controller="multiAddForecast" sidebar="false" id="CExPage" showheader="true" tabstyle="Bill__c">
<script language="JavaScript" type="text/javascript">
function CloseAndRefresh(){
window.parent.location.href="/{!$CurrentPage.parameters.id}"; self.close(); }
</script>
<apex:form >
<apex:pageBlock title="Forecast" >

<apex:pageBlockButtons >
<apex:pagemessages rendered="true" id="msg2" />
<apex:commandButton value="Add New" action="{!add}" rerender="rows" status="outStatus"/>
<apex:commandButton action="{!save}" value="Save and Close" oncomplete="javascript:CloseAndRefresh()" rerender="rows,msg2" status="outStatus"/>
</apex:pageBlockButtons>

<apex:pageBlockTable width="80%" align="center" value="{!cexs}" var="c" id="rows" >

<apex:column width="30%" headerValue="Forecasted Amount"><apex:inputField value="{!c.Forecasted_Number__c}" required="true"/></apex:column>
<apex:column width="30%" headerValue="Current Price"><apex:inputField value="{!c.Price_Per_Month__c}" required="true" /></apex:column>
<apex:column headervalue="Month"><apex:outputField value="{!c.Month__c}" /></apex:column>

</apex:pageBlockTable>       
</apex:pageblock>    
</apex:form>
</apex:page>

Controller:

public class multiAddForecast {

public List <Bill__c> CExList {get; set;}
public Id cID = ApexPages.currentPage().getParameters().get('Id'); //grab the Account ID
public Id getID {get; set;}

public multiAddForecast(){
    CExList = new List<Bill__c>();
    Date lastDate = getStartDateByAccount();
    Decimal Lastcurrency = getCurrentPriceAccount();
    addInternal(1,lastDate, Lastcurrency);
    addInternal(2,lastDate, Lastcurrency);
    addInternal(3,lastDate, Lastcurrency);

}

public List <Bill__c> getCExs() {
 return CExList;}

public void setAccounts(List <Bill__c> cexs) {
   CExList = cexs;}

public PageReference save() {//upsert records on save
upsert CExList;
ApexPages.Message myMsg = new ApexPages.message(ApexPages.Severity.Info, 'Records Saved Successfully'); //show confirmation message on save
ApexPages.addMessage(myMsg);
return null;}


public PageReference add() {

    Date lastDate = getStartDateByAccount();
    Decimal Lastcurrency = getCurrentPriceAccount();
    addInternal(CExList.size()+1,lastDate, Lastcurrency);

    return null;
}


private void addInternal(integer numMonth,Date startMonth, Decimal curr){
    Date lineDate = startMonth.addMonths(numMonth);
    Monthly_Cloud_Bill__c newObj = New Bill__c(Account__c = cID);
    newObj.Billing_Month__c = lineDate;
    newObj.Price_Per_Month__c = curr;
    CExList.add(newObj);
}    

private Date getStartDateByAccount(){
    Account account = [Select Last_Billed__c, Current_Price__c From Account Where Id = :cID];
    return account.Last_Billed__c;

}

private Decimal getCurrentPriceAccount(){
    Account account2 = [Select Current_Price__c From Account Where Id = :cID];
    return account2.Current_Price__c;

}

}

UPDATED Code: thanks @mast0r, i published below the updated code. one problem: when trying to remove a row, i'm getting the following error: "List index out of bounds: 6 Error is in expression '{!removeNewObject}' in component in page multiaddforecast". Can you assist solving this??

Class:

public class multiAddForecast {

public List <Monthly_Cloud_Bill__c> CExList {get; set;}
public Id cID = ApexPages.currentPage().getParameters().get('Id'); //grab the Account ID
public Id getID {get; set;}
public Integer numberOfRowToRemove { get; set; }




public multiAddForecast(){
    CExList = new List<Monthly_Cloud_Bill__c>();
    Date lastDate = getStartDateByAccount();
    Decimal Lastcurrency = getCurrentPriceAccount();
    addInternal(1,lastDate, Lastcurrency);
    addInternal(2,lastDate, Lastcurrency);
    addInternal(3,lastDate, Lastcurrency);


}

public List <Monthly_Cloud_Bill__c> getCExs() {
 return CExList;}

public void setAccounts(List <Monthly_Cloud_Bill__c> cexs) {
   CExList = cexs;}

public PageReference save() {//upsert records on save
upsert CExList;
ApexPages.Message myMsg = new ApexPages.message(ApexPages.Severity.Info, 'Records Saved Successfully'); //show confirmation message on save
ApexPages.addMessage(myMsg);
return null;}


public PageReference add() {

    Date lastDate = getStartDateByAccount();
    Decimal Lastcurrency = getCurrentPriceAccount();
    addInternal(CExList.size()+1,lastDate, Lastcurrency);

    return null;
}



private void addInternal(integer numMonth,Date startMonth, Decimal curr){
    Date lineDate = startMonth.addMonths(numMonth);
    Monthly_Cloud_Bill__c newObj = New Monthly_Cloud_Bill__c(Account__c = cID);
    newObj.Billing_Month__c = lineDate;
    newObj.Effective_Price_Per_VM_Per_Month__c = curr;
    CExList.add(newObj);
}



private Date getStartDateByAccount(){
    Account account = [Select Last_Cloud_Billed__c, Current_Per_VM_Price__c From Account Where Id = :cID];
    return account.Last_Cloud_Billed__c;

}

private Decimal getCurrentPriceAccount(){
    Account account2 = [Select Current_Per_VM_Price__c From Account Where Id = :cID];
    return account2.Current_Per_VM_Price__c;

}

  // The method to remove an item from the list
    public PageReference removeNewObject(){

        CExList.remove(numberOfRowToRemove);  

        return null;
    }

}

Visualforce:

<apex:page controller="multiAddForecast" sidebar="false" id="CExPage" showheader="true" tabstyle="Monthly_Cloud_Bill__c">
<script language="JavaScript" type="text/javascript">
function CloseAndRefresh(){
window.parent.location.href="/{!$CurrentPage.parameters.id}"; self.close(); }
</script>
<apex:form >
<apex:pageBlock title="Forecast" >

<apex:variable value="{!0}" var="rowNumber" />

<apex:pageBlockButtons >
<apex:pagemessages rendered="true" id="msg2" />
<apex:commandButton value="Add New" action="{!add}" rerender="rows" status="outStatus"/>
<apex:commandButton action="{!save}" value="Save and Close" oncomplete="javascript:CloseAndRefresh()" rerender="rows,msg2" status="outStatus"/>
</apex:pageBlockButtons>

<!-- Here we will use an extra variable to define a row number -->
<apex:outputPanel id="panelWithVar">
    <apex:variable value="{!0}" var="rowNumber" />
</apex:outputPanel>

<!-- A list with new items -->
<apex:pageBlockTable width="80%" align="center" value="{!cexs}" var="c" id="rows" >

 <apex:column width="5%">
        <apex:commandButton action="{!removeNewObject}" value=" X " reRender="rows,panelWithVar">
            <apex:param name="p1" value="{!rowNumber}" assignTo="{!numberOfRowToRemove}"/>
        </apex:commandButton>
    </apex:column> 

<apex:column width="30%" headerValue="Forecasted Amount">
    <apex:inputField value="{!c.Forecasted_Number_of_VMs__c}" required="false"/>
</apex:column>
<apex:column width="30%" headerValue="Current Per VM Price">
    <apex:inputField value="{!c.Effective_Price_Per_VM_Per_Month__c}" required="true"/>
</apex:column>
<apex:column headervalue="Billing Month">
    <apex:outputField value="{!c.Billing_Month__c}" />
    <apex:variable var="rowNumber" value="{!rowNumber + 1}" /> 
</apex:column>

</apex:pageBlockTable>

</apex:pageblock>

</apex:form>
</apex:page>
  • We must increment the variable rowNumber only one time in the last column, this variable represents the entry number in the list. In your code this variable was incremented 3 times and the list index was broken. I have corrected your last visualforce page code. Try it. – Sergej Utko Apr 23 '13 at 8:24
  • thanks! it still happens when I add a new row and then try to remove it.. – Itay B Apr 23 '13 at 9:16
  • One more mistake: for the button Add new set the parameter reRender="rows,panelWithVar" (panelWithVar need to be rerendered too). – Sergej Utko Apr 23 '13 at 9:57
  • nice, thank you!! one last question...the input fields are set to required, so I can't remove the row unless I enter a value and then remove the row. Can the "Remove row" bypass the required field, or I need to create a validation in the VF / class? – Itay B Apr 23 '13 at 10:13
  • I think you can try with immediate="true" parameter for the "X" button: <apex:commandButton action="{!removeNewObject}" value=" X " immediate="true" /> This button will ignore the mandatory fields then. – Sergej Utko Apr 23 '13 at 10:19
9

I have a simple example for you, where you can add entries to the list and show this list on the visualforce page and separately remove these entries. This looks like this:

enter image description here

The idea is to use an extra variable to define a row number to remove. Try to reproduce my example and use the logic in your code:

Class:

public with sharing class test1 {

    public List<OpportunityContactRole> objectsToInsert { get; set; } 
    public Integer numberOfRowToRemove { get; set; }
    public Opportunity opp { get; set; }

    public test1()
    {
        objectsToInsert = new List<OpportunityContactRole>();
        opp = [ Select Id From Opportunity Limit 1 ];
    }

    // The method to add a new item to the list
    public PageReference addNewObject(){

        OpportunityContactRole newObject = new OpportunityContactRole(OpportunityId = opp.id);
        objectsToInsert.add(newObject);

        return null;
    }

    // The method to remove an item from the list
    public PageReference removeNewObject(){

        objectsToInsert.remove(numberOfRowToRemove);  

        return null;
    }
}

Page:

<apex:page controller="test1">
<apex:form>

<apex:pageBlock>
<apex:variable value="{!0}" var="rowNumber" />

<!-- A main button to add a new item -->
<apex:commandButton value="Add" action="{!addNewObject}" reRender="newItems,panelWithVar" immediate="true"/>

<!-- Here we will use an extra variable to define a row number -->
<apex:outputPanel id="panelWithVar">
    <apex:variable value="{!0}" var="rowNumber" />
</apex:outputPanel>

<!-- A list with new items -->
<apex:pageBlockTable value="{!objectsToInsert}" var="item" id="newItems">
    <!-- A button to remove individual entry. 
         We must to pass the line number to define a list entry number to remove -->
    <apex:column width="5%">
        <apex:commandButton action="{!removeNewObject}" value=" X " reRender="newItems,panelWithVar">
            <apex:param name="p1" value="{!rowNumber}" assignTo="{!numberOfRowToRemove}"/>
        </apex:commandButton>
    </apex:column>

    <!-- Moreover here we incrementing the row number variable -->
    <apex:column headerValue="{!$ObjectType.OpportunityContactRole.fields.Role.label}">
        <apex:inputField value="{!item.Role}"/>
        <apex:variable var="rowNumber" value="{!rowNumber + 1}" />
    </apex:column>

</apex:pageBlockTable>

</apex:pageBlock>

</apex:form>
</apex:page>

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.