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
steve_andersensteve_andersen 

DataTable Row numbers?

I want to have a string in each row of a data table that includes the Row number.

Payment 1, Payment 2, Payment 3, etc.

In js I would just use the row counter. Anything analogous in a VF datatable?

Thanks,
Steve
Ron HessRon Hess
not really

i've done this by building a data model that holds a row, and a row number

i access the row contents and the row number using getters.

here is a portion of my RSS feed class that does this, when building the entry ( in the controller, in a loop) i set the index

then it is available in the Visualforce page as "{!index}"

Code:
    public class RssEntry {

        public RssEntry(Xmldom.Element ein, integer index) { 
            e = ein; idx = index;
        }
[..deleted..]
  public integer getIndex() { return idx; } Xmldom.Element e; integer idx; }

 

steve_andersensteve_andersen
Sorry Ron, I'm a bit slow on this stuff.

I've got a dataTable that has a list of objects as the value. My understanding is that the var is then each object.

<apex:dataTable value="{!payments}" var="OppPayment" id="theTable">

If you're creating a more complex data structure, how do you feed it to a dataTable so that you can make that Index call but also have an input field for the objects?

<apex:column >
<apex:facet name="header">Installment #</apex:facet>
<apex:outputText value="{!InstallmentCount}"/>
</apex:column>
<apex:column >
<apex:facet name="header">Amount</apex:facet>
<apex:inputField value="{!OppPayment.Amount__c}"/>
</apex:column>



Here is my full code for VF:
<apex:page controller="ONEN_Installment_Wizard" tabStyle="Opportunity">
    <apex:sectionHeader title="Installments" subtitle="Create multiple installments for this Opportunity"/>
    <apex:pageBlock title="Current Opportunity Info">
        <apex:panelGrid columns="2" id="theGrid">
            <apex:outputText value="Name: " styleClass="labelCol"/>
            <apex:outputText value="{!currentOpp.Name}" styleClass="dataCol" />
            <apex:outputText value="Amount: " styleClass="labelCol" />
            <apex:outputText value="{!currentOpp.Amount}" styleClass="dataCol" />
            <apex:outputText value="Stage: " styleClass="labelCol" />
            <apex:outputText value="{!currentOpp.StageName}" styleClass="dataCol"  />
            <apex:outputText value="Description: " styleClass="labelCol" />
            <apex:outputText value="{!currentOpp.Description}" styleClass="dataCol"  />
        </apex:panelGrid>
    </apex:pageBlock>   
    
    <apex:form >
    <apex:pageBlock title="Create a Payment Schedule" mode="edit">
        <apex:panelGrid columns="3" id="theGrid">
            <apex:outputText value="# of Installments" styleClass="labelCol"/>
            <apex:outputText value="Date of 1st Installment" styleClass="labelCol"/>
            <apex:outputText value="Interval" styleClass="labelCol"/>            
            <apex:selectList value="{!numberofinstallments}" id="installmentCount" multiselect="false" size="1">
                <apex:selectOptions value="{!items}"/>
            </apex:selectList>
            <apex:inputField value="{!thisInstallment.Date__c}"/> 
            <apex:outputPanel id="thePanel">
                <apex:selectList value="{!interval}" id="intervals" multiselect="false" size="1">
                    <apex:selectOptions value="{!intervals}"/>                
                </apex:selectList>
                <apex:selectList value="{!intervalunit}" id="intervalunits" multiselect="false" size="1">
                    <apex:selectOptions value="{!intervalunits}"/>                
                </apex:selectList>
            </apex:outputPanel>
        </apex:panelGrid>
    <apex:pageBlockButtons >
    <apex:commandButton rerender="installmenttable" value="Next"/>
    </apex:pageBlockButtons>
    
    </apex:pageBlock>
    </apex:form>
    
    <apex:form >
    <apex:pageBlock title="Installments to be Created" mode="edit">
        <apex:outputPanel id="installmenttable">
           
           
           <apex:dataTable value="{!payments}" var="OppPayment" id="theTable" rowClasses="odd,even" styleClass="tableClass">

            <apex:column >
                <apex:facet name="header">Installment #</apex:facet>
                <apex:outputText value="{!InstallmentCount}"/>
            </apex:column>
            <apex:column >
                <apex:facet name="header">Amount</apex:facet>
                <apex:inputField value="{!OppPayment.Amount__c}"/>
            </apex:column>
            <apex:column >
                <apex:facet name="header">Date</apex:facet>
                <apex:inputField value="{!OppPayment.Date__c}"/>
            </apex:column>
            <apex:column >
                <apex:facet name="header">Paid—</apex:facet>
                <apex:inputField value="{!OppPayment.Paid__c}"/>
            </apex:column>
            </apex:dataTable>
        </apex:outputPanel>
        <apex:pageBlockButtons >
       <apex:commandButton action="{!createInstallments}" value="Create"/>
        </apex:pageBlockButtons>
        
    </apex:pageBlock>
    </apex:form>
</apex:page>

 
And my controller:
public class ONEN_Installment_Wizard {
 
 //Opportunity for the opp we're coming from
    private final Opportunity currentOpp;
    
    //opp payment object for form field binding
    public OppPayment__c thisInstallment;
    
    //the integer value from the form
    private Integer selectedInstallmentCount;
    
    //constructor gets the opp from the passed in Id
    public ONEN_Installment_Wizard() {
        currentOpp= [select name, amount, stagename, description, closedate from Opportunity where id =:ApexPages.currentPage().getParameters().get('id')];
    }
    
    //get the current opportunity
    public Opportunity getCurrentOpp() {
     return currentOpp;
    }
    
    //list of items for picklist of the number of payments to be created
    public List<SelectOption> getItems() {
        List<SelectOption> options = new List<SelectOption>();
        options.add(new SelectOption('1','1'));
        options.add(new SelectOption('2','2'));
        options.add(new SelectOption('3','3'));
        options.add(new SelectOption('4','4'));
        options.add(new SelectOption('5','5'));
        options.add(new SelectOption('6','6'));
        options.add(new SelectOption('7','7'));
        options.add(new SelectOption('8','8'));
        options.add(new SelectOption('9','9'));
        options.add(new SelectOption('10','10'));
        options.add(new SelectOption('11','11'));
        options.add(new SelectOption('12','12'));
        return options;
    }
    
    //integer for the number of installments to create
    public Integer numberofinstallments { get {return numberofinstallments;} set {numberofinstallments = value;} }
    
    //integer to hold the interval chosen
    public Integer interval { get {return interval;} set {interval = value;} }
    
    
    
    //list of items for picklist of the interval between payments to be created
    public List<SelectOption> getIntervals() {
        List<SelectOption> options = new List<SelectOption>();
        options.add(new SelectOption('1','1'));
        options.add(new SelectOption('2','2'));
        options.add(new SelectOption('3','3'));
        options.add(new SelectOption('4','4'));
        options.add(new SelectOption('5','5'));
        options.add(new SelectOption('6','6'));
        options.add(new SelectOption('7','7'));
        options.add(new SelectOption('8','8'));
        options.add(new SelectOption('9','9'));
        options.add(new SelectOption('10','10'));
        options.add(new SelectOption('11','11'));
        options.add(new SelectOption('12','12'));
        return options;
    }
    
    //the unit of the interval
    public String intervalUnit { get {return intervalUnit;} set {intervalUnit = value;} }
    
    //list of items for picklist of the interval unit between payments to be created
    public List<SelectOption> getIntervalUnits() {
        List<SelectOption> options = new List<SelectOption>();
        options.add(new SelectOption('Week','Week'));
        options.add(new SelectOption('Month','Month'));
        options.add(new SelectOption('Year','Year'));
        return options;
    }
    
    //list to hold new payments
    private List<OppPayment__c> newPayments = new List<OppPayment__c>();
    
    //get the payments
    public List<OppPayment__c> getPayments() {
    
        newPayments.clear();
        
       // OppAmountFloat = parseFloat(String(OppAmount).substring(1,String(OppAmount).length).replace("\,",""));
        //Double OppAmountFloat = String(OppAmount).substring(1,currentOpp.Amount.length()).replace('\,','');
        Decimal OppAmountFloat = currentOpp.Amount;
        
  Decimal installCount = 0;
  installCount = numberofinstallments;
  //divide the amount by the number of installments, and deal with the remainder - can't get this to work
        Decimal paymentAmount = currentOpp.Amount/3;        
        
        for(Integer installmentcounter=0;installmentcounter<numberofinstallments;installmentcounter++){
         
       //get the interval unit
       
       //do the math of interval times interval unit and adding to the first payment date
            
            OppPayment__c firstOppPayment = new OppPayment__c();  
           // firstOppPayment.Name = 'Installment ' + (installmentcounter+1) + ' of ' + numberofinstallments;
            firstOppPayment.Opportunity__c=currentOpp.id;
            firstOppPayment.Opp_For_Installment__c=currentOpp.id;
            firstOppPayment.Date__c=thisInstallment.Date__c;
            firstOppPayment.IsInstallment__c=true;
            firstOppPayment.Amount__c = paymentAmount;
            newPayments.add(firstOppPayment);
        }        
        
        return newPayments ;
    }
    
    public OppPayment__c getThisInstallment() {
        if(thisInstallment== null) thisInstallment = new OppPayment__c(Date__c=currentOpp.closedate);
        return thisInstallment;
    }

    public PageReference createInstallments() {
        insert newPayments;
        // Send the user to the detail page for the new account.
        PageReference oldOppPage = new PageReference('/' + currentOpp.id);
        oldOppPage .setRedirect(true);
        return oldOppPage;
    }
 
 public Integer installmentCount = 0;
 
 public String getInstallmentCount() {
  string countstring;
  installmentCount++;
  return 'Payment # ' + installmentCount;
 }
}

 
Thanks for your help! And congrats on the Google stuff--great work!

Steve



steve_andersensteve_andersen
So I came up with a hacky work-around. The easiest way to get the row number from apex to my dataTable is to write it to a field on the object. Since I'm not exposing all fields on this form, I can put it in a field I'm not using:

Controller:
OppPayment__c firstOppPayment = new OppPayment__c();  
  firstOppPayment.Opportunity__c=currentOpp.id;
  firstOppPayment.Check_Number__c='Payment # ' + installmentcounter;
  .
  .
  .

Then in VF it's just an ouputText:

<apex:column >
   <apex:facet name="header">Installment #</apex:facet>
   <apex:outputText value="{!OppPayment.Check_Number__c}"/>
</apex:column>

 Then I just have to clean up that bogus data:

public PageReference createInstallments() {
   for (OppPayment__c thisPayment : newPayments) {
      thisPayment.Check_Number__c=null;
   }
   insert newPayments;
   // Send the user to the detail page for the new account.
   PageReference oldOppPage = new PageReference('/' + currentOpp.id);
   oldOppPage .setRedirect(true);
   return oldOppPage;
}

Ugly, but easy if you have a text field lying around...

I'd love to see an easier way to get row index while in a dataTable.

Thanks,
Steve



Ron HessRon Hess
would sort of look like this, where payments model list is a list of your wrapper object, 
it holds one opportunity and one index (installmentcount) , has getters for each

then the loop looks like this

Code:
<apex:dataTable value="{!payments_model_list}" var="model" id="theTable">

<apex:column >
  <apex:facet name="header">Installment #</apex:facet>
  <apex:outputText value="{!model.InstallmentCount}"/>
</apex:column>
<apex:column >
  <apex:facet name="header">Amount</apex:facet>
  <apex:inputField value="{!model.OppPayment.Amount__c}"/>
</apex:column>

the wrapper looks something like this
 
Code:
class payments_model {
 public opportunity opppayment {get;set;}
 public integer installmentcount { get;set;}
}


 

steve_andersensteve_andersen
Thanks Ron, that makes sense.

Is there any way to get param to work in my dataTable?

<apex:outputText value="Payment # {0}">
   <apex:param value="{!paymentNumber}"/>
</apex:outputText>

 
I got it to work, but couldn't get the param to increment with each row. So I get Payment # 0, Payment # 0, etc.

Does param value get set on instantiation of the dataTable and doesn't call out again? That's what seems to be happening.

Thanks,
Steve
Ron HessRon Hess
don't think it works that way

you need to have your output inside a repeat tag, and then using var="foo"
you access each member as {!foo.paymentNumber}

you still need the wrapper class to describe the data model, the payment number becomes part of your data model in the end.
Christopher_Alun_LewisChristopher_Alun_Lewis

I have a suggestion for any still looking to do this, that is simple and entirely visualforce tag based.

 

To give the rows numbers, you can simply use the <apex:variable> tag. Define the variable instance once just before the pageblock with a base value, then again inside a column in the table, this time incrementing the current value by 1 each time after the variable is used.

 

Here is a code example for a table of contacts related to an account:

 

 

<apex:page standardController="Account">
  
  <apex:variable var="rowIndex" value="{!1}"/>
    
  <apex:PageBlock >  
    <apex:PageBlockTable value="{!account.Contacts}" var="con">
      <apex:column >
        contact #{!rowIndex}
        <apex:variable value="{!rowIndex + 1}" var="rowIndex"/>               
      </apex:column>
      <apex:column value="{!con.Name}"/> 
      <apex:column value="{!con.Title}"/>        
      <apex:column value="{!con.Birthdate}"/>           
    </apex:pageBlockTable>
  </apex:PageBlock>     

</apex:page>

 

Hope that helps,

 

Christopher Alun Lewis

 

Check out the Christopher Alun Lewis Blog for similar Salesforce tips and samples!

Andrew B. DavisAndrew B. Davis
For everyone's reference, Salesforce doesn't recommend the approach of using <apex:variable> to create an iterator (http://www.salesforce.com/docs/developer/pages/Content/pages_compref_variable.htm) that Christopher mentions above, although Jeff Douglas likes it (http://blog.jeffdouglas.com/2010/04/02/visualforce-row-counter-for-iteration-components/) but says it doesn't work in <Apex:datatable> elements. Salesforce indicates that the functionality may break without notice in future updates. The method that Salesforce recommends and that works OK for <apex:datatable> elements is to create a wrapper class in Apex that contains an iterator (https://developer.salesforce.com/page/Wrapper_Class).