You need to sign in to do that
Don't have an account?
Michael Friedman 7
Visualforce sort two apex:pageblocktable elements on same page
I am new to visualforce and am having trouble getting sorting working on my page. My page has two pageblocktables on it that pull data from two different object dynamically based on fields that users input into a custom setting. I would like both tables to be sortable independently. The solution I have is working for one table, but not the other. As far as I can tell the code for both tables is identical. Not sure why there is a difference in behavior.
The table that works is pulling data from an object called Timesheet__c. It is the second table on the page. The table that doesn't is the first and is pulling from an object called Expense_Line__c.
Any help would be much appreciated!
Here is my page:
Here is my apex code:
The table that works is pulling data from an object called Timesheet__c. It is the second table on the page. The table that doesn't is the first and is pulling from an object called Expense_Line__c.
Any help would be much appreciated!
Here is my page:
<apex:page controller="invoicePickerClass" lightningStylesheets="TRUE"> <apex:form> <!-- Output panel to make the buttons live side-by-side --> <apex:outputPanel id="thePanel" layout="block"> <!-- Button to get Save changes and stay on form --> <apex:commandButton action="{!getSelected}" value="Save" id="Save"/> <!-- Button to Save changes and return to Invoice --> <apex:commandButton action="{!getSelectedandLeave}" value="Save and Done" id="SaveAndDone"/> </apex:outputPanel> <!--Panel grid that holds the two tables --> <!-- <apex:panelGrid columns="1" width="100%" columnClasses="pgCol"> --> <!-- Expense Line Table --> <apex:pageBlock title="Expense Line List" id="expenseLines"> <apex:pageBlockSection columns="1"> <!-- ExpenseLine List --> <apex:pageBlockTable value="{! ExpenseLines }" var="el" rendered="{!(expenseLines.size != 0)}" cellpadding="5"> <!-- Checkbox Column --> <apex:column > <apex:facet name="header"> <apex:inputCheckbox styleClass="checkEL" value="{!el.isSelectedEL}" onclick="checkAll(this,'checkEL')"/> </apex:facet> <apex:inputCheckbox styleClass="checkEL" value="{!el.isSelectedEL}" id="checkedone"> </apex:inputCheckbox> </apex:column> <!-- Dynamic Table Columns --> <apex:repeat value="{!ELCol}" var="elCol"> <apex:column> <apex:facet name="header"> <apex:commandLink action="{!elSortDir}" immediate="true" reRender="expenseLines" value="{!$ObjectType.Expense_Line__c.Fields[elCol].Label }"> <apex:param name="sortParam" assignTo="{!elSort}" value="{!elCol}"/> <apex:outputPanel> <apex:image value="{!IF(elSort = elCol,$Resource[elSortIMG], $Resource.Sortable)}"/> </apex:outputPanel> </apex:commandLink> </apex:facet> <apex:outputField value="{! el.exp[elCol] }"/> </apex:column> </apex:repeat> <!-- Make table inline editable --> <apex:inlineEditSupport event="ondblClick"/> </apex:pageBlockTable> <!-- Text to display if no data in the table --> <apex:outputText rendered="{!(expenseLines.size = 0)}" value="There are no Expenses to display." /> </apex:pageBlockSection> </apex:pageBlock> <!-- Timesheets Table --> <apex:pageBlock title="TimeSheet List" id="timeSheets"> <apex:pageBlockSection columns="1"> <!-- TimeSheet List --> <apex:pageBlockTable value="{! TimeSheets }" var="ts" rendered="{!(TimeSheets.size != 0)}" cellpadding="5"> <!-- Checkbox Column --> <apex:column> <apex:facet name="header"> <apex:inputCheckbox styleClass="checkTS" value="{!ts.isSelectedTS}" onclick="checkAll(this,'checkTS')"/> </apex:facet> <apex:inputCheckbox styleClass="checkTS" value="{!ts.isSelectedTS}" id="checkedone"> </apex:inputCheckbox> </apex:column> <!-- Dynamic table column --> <apex:repeat value="{!TSCol}" var="tsCol"> <apex:column> <apex:facet name="header"> <apex:commandLink action="{!tsSortDir}" immediate="true" reRender="timeSheets" value="{!$ObjectType.Timesheet__c.Fields[tsCol].Label }"> <apex:param name="sortParam" assignTo="{!tsSort}" value="{!tsCol}"/> <apex:outputPanel> <apex:image value="{!IF(tsSort = tsCol,$Resource[tsSortIMG], $Resource.Sortable)}"/> </apex:outputPanel> </apex:commandLink> </apex:facet> <apex:outputField value="{! ts.tsh[tsCol] }"/> </apex:column> </apex:repeat> <!-- Make table inline editable --> <apex:inlineEditSupport event="ondblClick"/> </apex:pageBlockTable> <!-- Text to display if no data for table --> <apex:outputText rendered="{!(TimeSheets.size = 0)}" value="There are no TimeSheets to display."/> </apex:pageBlockSection> </apex:pageBlock> <!-- </apex:panelGrid> --> </apex:form> <!-- Script that runs when check all is selected --> <script> function checkAll(cb, check) { var inputElem = document.getElementsByClassName(check); for(var i=0; i<inputElem.length; i++) { if(inputElem[i].id.indexOf("checkedone")!=-1) inputElem[i].checked = cb.checked; } } </script> <!-- Style needed if the tables are moved side-by-side --> <style type="text/css"> .pgCol{ width:50%; } </style> </apex:page>
Here is my apex code:
public with sharing class invoicePickerClass { //URL and other Parameters public String invId {get; set;} public String projId {get; set;} public static String recId {get; set;} //Sort Variables public String tsSort {get; set;} public String tsSortLast {get; set;} transient String tsSortDir {get; set;} public String tsSortDirLast {get; set;} public String elSort {get; set;} public String elSortLast {get; set;} transient String elSortDir {get; set;} public String elSortDirLast {get; set;} //Sort images public String tsSortIMG {get;set;} public String elSortIMG {get;set;} //Lists for synamic columns List<String> tsCol = new List<string>(); List<String> elCol = new List<string>(); //Wrapper class data public List<tsWrapper> tsList {get; set;} List<Timesheet__c> selectedTimeSheets = new List<Timesheet__c>(); List<Timesheet__c> unSelectedTimeSheets = new List<Timesheet__c>(); public List<elWrapper> elList {get; set;} List<Expense_Line__c> selectedExpenseLines = new List<Expense_Line__c>(); List<Expense_Line__c> unSelectedExpenseLines = new List<Expense_Line__c>(); //method to populate time sheet table using wrapper class public List<tsWrapper> getTimeSheets() { invId = Apexpages.currentPage().getparameters().get('invId'); projId = Apexpages.currentPage().getparameters().get('projId'); system.debug(tsSort+tsSortLast+tsSortDir+tsSortDirLast+tsSortIMG); if(tsSort == NULL){tsSort = 'Date__c'; tsSortDir = 'DESC';} system.debug(tsSort+tsSortLast+tsSortDir+tsSortDirLast+tsSortIMG); tsSortDir(); tsSortLast = tsSort; system.debug(tsSort+tsSortLast+tsSortDir+tsSortDirLast+tsSortIMG); List<string> columns = getColumns('Timesheet__c'); String qry = 'select Id, Invoice__c, Project__c, '+String.join(columns, ',')+' FROM Timesheet__c WHERE Project__c = :projId AND (Invoice__c = \'\' OR Invoice__c = :invId) ORDER BY '+tsSort+' '+tsSortDir; // if(tsList == NULL){ tsList = new List<tsWrapper>(); for(Timesheet__c tsh : Database.query(qry)){ tsList.add(new tsWrapper(tsh)); } // } return tsList; } //method to populate expense line table using wrapper class public List<elWrapper> getExpenseLines() { invId = Apexpages.currentPage().getparameters().get('invId'); projId = Apexpages.currentPage().getparameters().get('projId'); system.debug(elSort+elSortLast+elSortDir+elSortDirLast+elSortIMG); if(elSort == NULL){elSort = 'Date__c'; elSortDir = 'DESC';} system.debug(elSort+elSortLast+elSortDir+elSortDirLast+elSortIMG); elSortDir(); elSortLast = elSort; system.debug(elSort+elSortLast+elSortDir+elSortDirLast+elSortIMG); List<string> columns = getColumns('Expense_Line__c'); String qry = 'select Id, Invoice__c, Project__c, '+String.join(columns, ',')+' FROM Expense_Line__c WHERE Project__c = :projId AND (Invoice__c = \'\' OR Invoice__c = :invId) ORDER BY '+elSort+' DESC'; //if(elList == NULL){ elList = new List<elWrapper>(); for(Expense_Line__c exp : Database.query(qry)){ elList.add(new elWrapper(exp)); } //} return elList; } public List<String> getColumns(string obj){ List<InvoicePicker__c> ipCol = new List<InvoicePicker__c>(); List<String> columns = new List<String>(); if(obj=='Timesheet__c'){ ipCol = [select Field__c FROM InvoicePicker__c WHERE Object__c = :obj ORDER BY Column_Order__c ASC]; } else if(obj=='Expense_Line__c'){ ipCol = [select Field__c FROM InvoicePicker__c WHERE Object__c = :obj ORDER BY Column_Order__c ASC]; } for(InvoicePicker__c ip : ipCol){ columns.add(ip.Field__c); } return columns; } //method for dynamic columns for Timesheets public List<String> getTSCol(){ tsCol.clear(); tsCol.addAll(getColumns('Timesheet__c')); return tsCol; } //method for dynamic columns for Expense Lines public List<String> getELCol(){ elCol.clear(); elCol.addAll(getColumns('Expense_Line__c')); return elCol; } //Sort data table action public void tsSortDir() { if(tsSortLast == tsSort && tsSortDirLast == 'DESC'){tsSortDir = 'ASC';} else if(tsSortLast == tsSort && tsSortDirLast == 'ASC'){tsSortDir = 'DESC';} else{tsSortDir = 'DESC';} tsSortDirLast = tsSortDir; tsSortIMG = tsSortDir; } public void elSortDir() { if(elSortLast == elSort && elSortDirLast == 'DESC'){elSortDir = 'ASC';} else if(elSortLast == elSort && elSortDirLast == 'ASC'){elSortDir = 'DESC';} else{elSortDir = 'DESC';} elSortDirLast = elSortDir; elSortIMG = elSortDir; } //timesheet wrapper class public class tsWrapper{ public Timesheet__c tsh {get; set;} public Boolean isSelectedTS {get; set;} public tsWrapper(Timesheet__c ts){ tsh = ts; if(tsh.Invoice__c != NULL){ isSelectedTS = true; } else{isSelectedTS = false;} } } //Expense Line Wrapper public class elWrapper{ public Expense_Line__c exp{get; set;} public Boolean isSelectedEL {get; set;} public elWrapper(Expense_Line__c el){ exp = el; if(exp.Invoice__c != NULL){ isSelectedEL = true; } else{isSelectedEL = false;} } } //Original Processing of selected items public PageReference getSelectedEL(){ selectedExpenseLines.clear(); unSelectedExpenseLines.clear(); for(elWrapper elWrapper : this.elList){ if(elWrapper.isSelectedEL == true) { selectedExpenseLines.add(elWrapper.exp); } if(elWrapper.isSelectedEL == false){ unSelectedExpenseLines.add(elWrapper.exp); } } return null; } public PageReference getSelectedTS(){ selectedTimeSheets.clear(); unSelectedTimeSheets.clear(); for(tsWrapper tsWrapper : this.tsList){ if(tsWrapper.isSelectedTS == true) { selectedTimeSheets.add(tsWrapper.tsh); } if(tsWrapper.isSelectedTS == false){ unSelectedTimeSheets.add(tsWrapper.tsh); } } return null; } //wrapper class for Comparable Interface //public class sortN implements Comparable { // public String sortValue {get;set;} // public sortN(String sortName) { // sortValue = sortName; // } // public Integer compareTo(Object ObjToCompare) { // return sortValue.CompareTo(((sortN)ObjToCompare).sortValue); // } //} //Button method public PageReference getSelected(){ //get all selected and unselected records getSelectedEL(); getSelectedTS(); //process and update all selected and unselected records processTimeSheets(); processExpenseLines(); return NULL; } public PageReference getSelectedandLeave(){ //get all selected and unselected records getSelectedEL(); getSelectedTS(); //process and update all selected and unselected records processTimeSheets(); processExpenseLines(); //navigate back to invoice record PageReference pr = new PageReference('/'+invId); system.debug(pr); pr.setRedirect(true); return pr; } public void processTimeSheets(){ List<Timesheet__c> processedTimeSheets = new List<Timesheet__c>(); for(Timesheet__c t : selectedTimeSheets){ Timesheet__c newTimeSheet = new Timesheet__c(id=t.Id); newTimeSheet.Invoice__c = invId; Map<String, SObjectField> m = Timesheet__c.SObjectType.getDescribe().fields.getMap(); for(String f : tsCol){ DescribeFieldResult r = m.get(f).getDescribe(); if(r.isUpdateable()){ newTimeSheet.put(f, t.get(f)); } } processedTimeSheets.add(newTimeSheet); } for(Timesheet__c t : unSelectedTimeSheets){ Timesheet__c newTimeSheet = new Timesheet__c(id=t.Id); newTimeSheet.Invoice__c = null; Map<String, SObjectField> m = Timesheet__c.SObjectType.getDescribe().fields.getMap(); for(String f : tsCol){ DescribeFieldResult r = m.get(f).getDescribe(); if(r.isUpdateable()){ newTimeSheet.put(f, t.get(f)); } } processedTimeSheets.add(newTimeSheet); } update processedTimeSheets; } public void processExpenseLines(){ List<Expense_Line__c> processedExpenseLines = new List<Expense_Line__c>(); for(Expense_Line__c e : selectedExpenseLines){ Expense_Line__c newExpenseLines = new Expense_Line__c(id=e.Id); newExpenseLines.Invoice__c = invId; Map<String, SObjectField> m = Expense_Line__c.SObjectType.getDescribe().fields.getMap(); for(String f : elCol){ DescribeFieldResult r = m.get(f).getDescribe(); if(r.isUpdateable()){ newExpenseLines.put(f, e.get(f)); } } processedExpenseLines.add(newExpenseLines); } for(Expense_Line__c e : unSelectedExpenseLines){ Expense_Line__c newExpenseLines = new Expense_Line__c(id=e.Id); newExpenseLines.Invoice__c = null; Map<String, SObjectField> m = Expense_Line__c.SObjectType.getDescribe().fields.getMap(); for(String f : elCol){ DescribeFieldResult r = m.get(f).getDescribe(); if(r.isUpdateable()){ newExpenseLines.put(f, e.get(f)); } } processedExpenseLines.add(newExpenseLines); } update processedExpenseLines; } }
Thanks again for the help.
All Answers
I am not sure whether these really make a difference. Still, please give a try:
1. Change names of apex:param like sortParam1 for first table and sortParam2 for second table.
2. If that doesn't work, wrap <apex:pageBlock title="Expense Line List" id="expenseLines"> pagblock inside an outputpanel and rerender the outputpanel.
Thanks again for the help.