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>
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.Add new
set the parameterreRender="rows,panelWithVar"
(panelWithVar
need to be rerendered too).immediate="true"
parameter for the "X" button:<apex:commandButton action="{!removeNewObject}" value=" X " immediate="true" />
This button will ignore the mandatory fields then.