+ Start a Discussion
MLamb2005MLamb2005 

Issues with cell-level error msgs in PageBlockTable

I've built a PageBlockTable that allows users to enter multiple records at one time. The table itself is working fine, I can iterate through and grab the values I need without issue. I'm trying to add some dynamic error messaging to the table to let users know which fields/cells need their attention. I'm using outputText for the error messaging, and my hope is to have a dynamic style for each one, and just toggle "display:inline" and "display:none" from the Apex Controller.

 

However, I can't seem to access a paricular pair of outputText fields. My code ends up turning them on or off for an entire column. Any ideas? Thanks!

 

Visualforce page:

 

 

<apex:form id="theForm">
    
    <apex:sectionHeader title="New Lab Project Hours" subtitle="Lab Project Hour Edit"/>
        
    <apex:pageBlock title="Lab Project Hour Quick Entry" mode="edit">
    <apex:pageMessages id="error" />
        <apex:pageblockButtons >
            <apex:commandButton value="Save" style="padding-left:6px;padding-right:6px" action="{!save}" rerender="error,theForm" />
            <apex:commandButton value="Cancel" style="padding-left:6px;padding-right:6px" action="{!cancel}" rerender="error" />
        </apex:pageblockButtons>
        
        <apex:pageblockSection title="Record Information" columns="2">
            <apex:inputField value="{!Lab_Project_Hours__c.Lab_Project_Name__c}" id="LabProjectName"/>
            <apex:inputField value="{!Lab_Project_Hours__c.Lab_Overflow_Resource__c}" id="LabOverflowResource"/>
            <apex:inputField value="{!Lab_Project_Hours__c.Employee_Name__c}" id="EmployeeName"/>
            <apex:inputField value="{!Lab_Project_Hours__c.Hourly_Utilization_Rate__c}" id="HourlyUtilizationRate"/>
        </apex:pageblockSection>
        
        <apex:pageBlockSection columns="1" title="Hours Worked">
        
            <apex:pageBlockTable HeaderClass="centerHeader" style="width:600px;margin-left:15%" value="{!lphs}" var="a" id="hourTable">
                <apex:column headerValue="Date Worked" styleClass="columnStyle" style="width:35%">
                    <apex:inputField value="{!a.TimeDate__c}" styleClass="{!dateFieldError}" /> <br />
                    <apex:outputText value="Error:" styleClass="errorTextBold" style="{!dateError}" />
                    <apex:outputText value=" Invalid number" styleClass="errorTextBold" style="{!dateError}" />
                </apex:column> 
                
                <apex:column headerValue="Type of Hours" styleClass="columnStyle" style="width:25%">
                    <apex:inputField value="{!a.Type_of_Hours__c}" styleClass="{!typeFieldError}" /> <br />               
                    <apex:outputText value="Error:" styleClass="errorTextBold" style="{!typeError}" />
                    <apex:outputText value=" Invalid number" styleClass="errorText" style="{!typeError}" />
                </apex:column>                
                
                <apex:column headerValue="Number of Hours Worked" styleClass="columnStyle" style="width:40%">
                    <apex:inputField value="{!a.Number_of_Hours_Worked__c}" styleClass="{!numFieldError}" /> <br />                    
                    <apex:outputText value="Error:" styleClass="errorTextBold" style="{!numError}" />
                    <apex:outputText value=" Invalid number" styleClass="errorText" style="{!numError}" />
                </apex:column>
            </apex:pageBlockTable>
        </apex:pageBlockSection>
            
        <div style="text-align:center;width:600px;margin-left:15%;font-weight:bold">
            <apex:commandLink value="Add Row" action="{!addRow}" rerender="hourTable,error" immediate="true" /> 
                &nbsp;|&nbsp;&nbsp;
            <apex:commandLink value="Remove Row" action="{!removeRow}" rerender="hourTable,error" immediate="true" />
        </div>
            
    </apex:pageBlock>
    </apex:form>

 

Apex Controller (the relevant piece)

 

public class ControllerSetLabProjectHourEmployeeName{

  private final Lab_Project_Hours__c objLabProject;
  public List<Lab_Project_Hours__c> lphs {get; set;}
  public String returnURL {get; set;}
  
  public String dateError {get; set;}
  public String typeError {get; set;}
  public String numError {get; set;}
  public String dateFieldError {get; set;}
  public String typeFieldError {get; set;}
  public String numFieldError {get; set;}

  // Constructor method
  public ControllerSetLabProjectHourEmployeeName(ApexPages.StandardController stdController){    
    this.objLabProject = (Lab_Project_Hours__c) stdController.getRecord();
    
    dateError = 'display:none;';
    typeError = 'display:none;';
    numError = 'display:none;';
    dateFieldError = '';
    typeFieldError = '';
    numFieldError = '';
         
    lphs = new List<Lab_Project_Hours__c>();
    for(Integer i=0; i<5; i++)
       lphs.add(New Lab_Project_Hours__c());
       
    try{
       User currentUser = [Select Id, Employee_Page__c From User Where Id = : UserInfo.getUserId() Limit 1];
       if(currentUser.Employee_Page__c != null){
         List<Employee__c> listEmployee = [Select Id, Name From Employee__c where Id = : currentUser.Employee_Page__c Limit 1];
         if(listEmployee.size() > 0){
            objLabProject.Employee_Name__c = listEmployee.get(0).Id;
         }  
       } 
     }
     catch(Exception ex){
       ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.FATAL,'Something unexpected happened, please contact an Administrator.'));
     }  
               
     Map<String, String> parentURL = ApexPages.currentPage().getParameters();
     returnURL = parentURL.get('retURL'); 
  }
  
  public void save(){
    Integer numOfRows = lphs.size();
    Integer count=0, totalCount=0, i=0, dateBlank=0, typeBlank=0, numBlank=0;
    String incompleteRows = '';
    
    //Make sure that the entire table isn't blank, and report an error if it is
    for(i=0; i<numOfRows; i++)
      if(lphs[i].TimeDate__c == null && lphs[i].Type_of_Hours__c == null && lphs[i].Number_of_Hours_Worked__c == null)
        count++;
    if(count == numOfRows)
      ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'You must fill out at least one row to submit hours.'));
    
    count=0;
    totalCount=0;
    
    for(i=0; i<numOfRows; i++) {
      if(lphs[i].TimeDate__c == null){
        count++; dateBlank=1;}
      if(lphs[i].Type_of_Hours__c == null){
        count++; typeBlank=1;}
      if(lphs[i].Number_of_Hours_Worked__c == null){
        count++; numBlank=1;}
            
      totalCount = totalCount + count;
      if(count > 0 && count <3){
        incompleteRows = incompleteRows + (i+1) + ' ';
        
        if(dateBlank == 1){
          dateError = 'display:inline;';
          dateFieldError = 'errorField';
        }
        if(typeBlank == 1){
          typeError = 'display:inline;';
          typeFieldError = 'errorField';
        } 
        if(numBlank == 1){
          numError = 'display:inline;';
          numFieldError = 'errorField';
        } 
      }
         
      count=0;
      dateBlank=0;
      typeBlank=0;
      numBlank=0;
    }
      
    if(totalCount == numOfRows)
      ApexPages.addMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'You must fill out at least one row to submit hours.'));

    if(incompleteRows.length() > 0)
      ApexPages.AddMessage(new ApexPages.Message(ApexPages.Severity.ERROR,'The following rows are incomplete and need to be fixed: ' + incompleteRows));
    
   // PageReference pageRef = new PageReference(returnURL);
   // return pageRef;
  }
}

 

 

 

 

Best Answer chosen by Admin (Salesforce Developers) 
MLamb2005MLamb2005

Ok, finally got this solved, but it wasn't pretty to make it look like I wanted. I added a bunch of new fields (like dateError__c below) to the object so I could conditionally check and display errors on each row, without affecting the other rows. Since each row is created dynamically in the pageBlockTable, you can reference a.<field_name> for a unique row.

 

 

<apex:column headerValue="Date Worked" styleClass="columnStyle" style="width:35%">
                    <apex:inputField value="{!a.TimeDate__c}" styleClass="{!a.dateFieldError__c}" /> <br />
                    <apex:inputField value="{!a.dateError__c}" style="display:none;" />
                    <apex:inputField value="{!a.dateFieldError__c}" style="display:none;" />
                    <apex:outputText value="Error: " styleClass="errorTextBold" rendered="{!a.dateError__c}" />
                    <apex:outputText value="{!a.dateErrorMessage__c}" styleClass="errorText" rendered="{!a.dateError__c}" />  
                </apex:column> 

 

So I can use this in the controller to feed in the appropriate error conditions on a row-by-row basis:

 

 if(dateBlank == 1){            
                lphs[i].dateError__c = true;
                lphs[i].dateFieldError__c = 'errorField';
                lphs[i].dateErrorMessage__c = 'Enter a date';
            }

 

Wasn't as pretty as I wanted it to be, but it got the job done.

 

 

All Answers

AvromAvrom

I'm not quite sure why you're doing this with display='hidden' at all--that's usually used to show/hide things *without* a round-trip to the server; since you need one anyway (to rerun the constructor), you'd probably be better off just using the rendered attribute in this case.

 

e.g., instead of

 

<apex:outputText value="Error:" styleClass="errorTextBold" style="{!typeError}" />

 

Try

<apex:outputText value="Error:" styleClass="errorTextBold" rendered="{!ISBLANK(a.TimeData__c}" />

 

 

 

MLamb2005MLamb2005

Thanks for the input, but that's not quite what I'm after. If I use your code, then when I reach the page the first time all the error conditions will be shown by default. What I'm going for is to conditionally display a message in a cell based on the other inputs for that row (i.e. if they enter 2 of 3 data points for a row, I want to display the error message in that 3rd cell.

 

But, what you gave me does allow me to conditionally turn on custom error messaging at the cell level, which is progress. Off to try and bridge that last gap!

MLamb2005MLamb2005

Ok, finally got this solved, but it wasn't pretty to make it look like I wanted. I added a bunch of new fields (like dateError__c below) to the object so I could conditionally check and display errors on each row, without affecting the other rows. Since each row is created dynamically in the pageBlockTable, you can reference a.<field_name> for a unique row.

 

 

<apex:column headerValue="Date Worked" styleClass="columnStyle" style="width:35%">
                    <apex:inputField value="{!a.TimeDate__c}" styleClass="{!a.dateFieldError__c}" /> <br />
                    <apex:inputField value="{!a.dateError__c}" style="display:none;" />
                    <apex:inputField value="{!a.dateFieldError__c}" style="display:none;" />
                    <apex:outputText value="Error: " styleClass="errorTextBold" rendered="{!a.dateError__c}" />
                    <apex:outputText value="{!a.dateErrorMessage__c}" styleClass="errorText" rendered="{!a.dateError__c}" />  
                </apex:column> 

 

So I can use this in the controller to feed in the appropriate error conditions on a row-by-row basis:

 

 if(dateBlank == 1){            
                lphs[i].dateError__c = true;
                lphs[i].dateFieldError__c = 'errorField';
                lphs[i].dateErrorMessage__c = 'Enter a date';
            }

 

Wasn't as pretty as I wanted it to be, but it got the job done.

 

 

This was selected as the best answer