-
ChatterFeed
-
0Best Answers
-
0Likes Received
-
0Likes Given
-
2Questions
-
4Replies
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; } }
- Michael Friedman 7
- October 05, 2017
- Like
- 0
Lightning Component Upsert - Attempted to upsert a null list
I am using the Expense__c tracker app as a template to create a custom lightning component for adding new Events. When I click save on the form, the log in the developer console returns an error: Attempted to upsert a null list.
Here is my Component:
Here is my Helper:
Any ideas on how to troubleshoot would be appreciated.
Here is my Component:
<aura:component controller="EventController" implements="force:appHostable,flexipage:availableForAllPageTypes" access="global"> <aura:attribute name="allDay" type="Boolean" default="False"/> <aura:attribute name="events" type="Event[]"/> <aura:attribute name="newEvent" type="Event" default="{ 'sobjectType': 'Event', 'Subject': 'Default Subject', 'OwnerId': '005j000000BRyZ1AAL', 'StartDateTime': 'now()', 'WhoId': '005j000000BRyZ1AAL', 'WhatId': '00Q63000001qAPqEAM', 'Consult_Amount__c': '123.10', 'Event_Status__c': 'Completed', 'Event_Type__c': 'Lunch', 'DurationInMinutes': '30' }"/> <!--Assigned To Form Element --> <ui:inputSelect label="Assigned To" multiple="false" required="true"> <ui:inputSelectOption text="All Primary" label="All Contacts" value="true"/> <ui:inputSelectOption text="All Primary" label="All Primary"/> <ui:inputSelectOption text="All Secondary" label="All Secondary"/> </ui:inputSelect> <!--Subject Form Element --> <ui:inputText label="Subject" placeholder="Enter Subject" value="{!v.newEvent.Subject}"/> <!--All Day Event Form Element --> <ui:inputCheckbox label="All Day Event" value="{!v.newEvent.IsAllDayEvent}" /> <!--Renders Date or DateTime UI Input based on All Day Event Check Box --> <aura:if isTrue="{!v.newEvent.IsAllDayEvent}"> <!--Start/End Date Form Elements --> <ui:inputDate aura:id="startdate" label="Start Date" value="{!v.newEvent.StartDateTime}" displayDatePicker="true" /> <ui:inputDate aura:id="enddate" label="End Date" value="{!v.newEvent.EndDateTime}" displayDatePicker="true" /> <aura:set attribute="else"> <!--Start/End DateTime Form Elements --> <ui:inputDateTime aura:id="startdatetime" label="Start Date" class="field" value="{!v.newEvent.StartDateTime}" displayDatePicker="true" /> <ui:inputDateTime aura:id="enddatetime" label="End Date" class="field" value="{!v.newEvent.EndDateTime}" displayDatePicker="true" /> </aura:set> </aura:if> <!--Invitee Form Element --> <ui:inputSelect label="Invitees Of This Event" multiple="True" required="true"> <ui:inputSelectOption text="All Primary" label="All Contacts" value="true"/> <ui:inputSelectOption text="All Primary" label="All Primary"/> <ui:inputSelectOption text="All Secondary" label="All Secondary"/> </ui:inputSelect> <!--Event Type Form Element --> <ui:inputSelect label="Event Type" multiple="False" required="true"> <ui:inputSelectOption text="All Primary" label="All Contacts" value="true"/> <ui:inputSelectOption text="All Primary" label="All Primary"/> <ui:inputSelectOption text="All Secondary" label="All Secondary"/> </ui:inputSelect> <!--Event Status Type Form Element --> <ui:inputSelect label="Event Status Type" multiple="False" required="true"> <ui:inputSelectOption text="Completed" label="Completed" value="true"/> <ui:inputSelectOption text="Canceled" label="Canceled"/> <ui:inputSelectOption text="No/Show" label="No/Show"/> </ui:inputSelect> <!--Rescheduled from Prior Consult Form Element --> <ui:inputCheckbox label="Rescheduled from Prior Consult" value=""/> <!--Is Paid Consult Form Element --> <ui:inputCheckbox label="Is Paid Consult" value=""/> <!--Consult Amount Form Element --> <ui:inputText label="Consult Amount" value="Consult Amount" required="true"/> <!--Related To Form Element --> <ui:inputSelect label="Related To" multiple="False" required="true"> <ui:inputSelectOption text="Matter" label="Matter" value="true"/> <ui:inputSelectOption text="Prospect" label="Prospect"/> </ui:inputSelect> <!--Save Event Button--> <ui:button label="Save" press="{!c.createEvent}"/> </aura:component>Here is my JS Controller:
({ createEvent : function(component, event, helper) { // Validate form fields // Pass form data to a helper function var newEvent = component.get("v.newEvent"); helper.createEvent(component, newEvent); } })
Here is my Helper:
({ createEvent: function(component, event) { //Save the event and update the view this.upsertEvent(component, event, function(a) { var events = component.get("v.events"); events.push(a.getReturnValue()); component.set("v.events", events); }); }, upsertEvent : function(component, event, callback) { var action = component.get("c.saveEvent"); action.setParams({ 'event': event }); if (callback) { action.setCallback(this, callback); } $A.enqueueAction(action); } })Here is my Apex Controller:
public with sharing class EventController { @AuraEnabled public static List<Event> getEvents() { String runningUser = UserInfo.getUserId(); List<Event> events = Database.query( 'SELECT Id, Subject, WhoId, WhatId, EndDateTime, StartDateTime, Matter_Type__c, Color_Code__c, Type, Event_Type__c, OwnerId FROM Event WHERE OwnerId = :runningUser AND (StartDateTime = LAST_N_DAYS:45 OR StartDateTime = NEXT_N_DAYS:45)'); //Add isAccessible() check return events; } @AuraEnabled // Retrieve all primary contacts public static List<Event> getConsult() { List<Event> consultEvents = [SELECT Id, Subject, WhoId, WhatId, EndDateTime, StartDateTime, ActivityDate, OwnerId, Type FROM Event WHERE Event_Type__c = 'Consult' AND OwnerId = '005j000000BRyZ1']; //Add isAccessible() check return consultEvents; } @AuraEnabled public static Event saveEvent(Event event) { // Perform isUpdateable() check here upsert event; return event; } }The extra code in the controller is for another part of the app. It looks like the data is being passed to the Apex controller from the component and that the Apex controller is set up the same way as the example.
Any ideas on how to troubleshoot would be appreciated.
- Michael Friedman 7
- October 12, 2016
- Like
- 0
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; } }
- Michael Friedman 7
- October 05, 2017
- Like
- 0
Lightning Component Upsert - Attempted to upsert a null list
I am using the Expense__c tracker app as a template to create a custom lightning component for adding new Events. When I click save on the form, the log in the developer console returns an error: Attempted to upsert a null list.
Here is my Component:
Here is my Helper:
Any ideas on how to troubleshoot would be appreciated.
Here is my Component:
<aura:component controller="EventController" implements="force:appHostable,flexipage:availableForAllPageTypes" access="global"> <aura:attribute name="allDay" type="Boolean" default="False"/> <aura:attribute name="events" type="Event[]"/> <aura:attribute name="newEvent" type="Event" default="{ 'sobjectType': 'Event', 'Subject': 'Default Subject', 'OwnerId': '005j000000BRyZ1AAL', 'StartDateTime': 'now()', 'WhoId': '005j000000BRyZ1AAL', 'WhatId': '00Q63000001qAPqEAM', 'Consult_Amount__c': '123.10', 'Event_Status__c': 'Completed', 'Event_Type__c': 'Lunch', 'DurationInMinutes': '30' }"/> <!--Assigned To Form Element --> <ui:inputSelect label="Assigned To" multiple="false" required="true"> <ui:inputSelectOption text="All Primary" label="All Contacts" value="true"/> <ui:inputSelectOption text="All Primary" label="All Primary"/> <ui:inputSelectOption text="All Secondary" label="All Secondary"/> </ui:inputSelect> <!--Subject Form Element --> <ui:inputText label="Subject" placeholder="Enter Subject" value="{!v.newEvent.Subject}"/> <!--All Day Event Form Element --> <ui:inputCheckbox label="All Day Event" value="{!v.newEvent.IsAllDayEvent}" /> <!--Renders Date or DateTime UI Input based on All Day Event Check Box --> <aura:if isTrue="{!v.newEvent.IsAllDayEvent}"> <!--Start/End Date Form Elements --> <ui:inputDate aura:id="startdate" label="Start Date" value="{!v.newEvent.StartDateTime}" displayDatePicker="true" /> <ui:inputDate aura:id="enddate" label="End Date" value="{!v.newEvent.EndDateTime}" displayDatePicker="true" /> <aura:set attribute="else"> <!--Start/End DateTime Form Elements --> <ui:inputDateTime aura:id="startdatetime" label="Start Date" class="field" value="{!v.newEvent.StartDateTime}" displayDatePicker="true" /> <ui:inputDateTime aura:id="enddatetime" label="End Date" class="field" value="{!v.newEvent.EndDateTime}" displayDatePicker="true" /> </aura:set> </aura:if> <!--Invitee Form Element --> <ui:inputSelect label="Invitees Of This Event" multiple="True" required="true"> <ui:inputSelectOption text="All Primary" label="All Contacts" value="true"/> <ui:inputSelectOption text="All Primary" label="All Primary"/> <ui:inputSelectOption text="All Secondary" label="All Secondary"/> </ui:inputSelect> <!--Event Type Form Element --> <ui:inputSelect label="Event Type" multiple="False" required="true"> <ui:inputSelectOption text="All Primary" label="All Contacts" value="true"/> <ui:inputSelectOption text="All Primary" label="All Primary"/> <ui:inputSelectOption text="All Secondary" label="All Secondary"/> </ui:inputSelect> <!--Event Status Type Form Element --> <ui:inputSelect label="Event Status Type" multiple="False" required="true"> <ui:inputSelectOption text="Completed" label="Completed" value="true"/> <ui:inputSelectOption text="Canceled" label="Canceled"/> <ui:inputSelectOption text="No/Show" label="No/Show"/> </ui:inputSelect> <!--Rescheduled from Prior Consult Form Element --> <ui:inputCheckbox label="Rescheduled from Prior Consult" value=""/> <!--Is Paid Consult Form Element --> <ui:inputCheckbox label="Is Paid Consult" value=""/> <!--Consult Amount Form Element --> <ui:inputText label="Consult Amount" value="Consult Amount" required="true"/> <!--Related To Form Element --> <ui:inputSelect label="Related To" multiple="False" required="true"> <ui:inputSelectOption text="Matter" label="Matter" value="true"/> <ui:inputSelectOption text="Prospect" label="Prospect"/> </ui:inputSelect> <!--Save Event Button--> <ui:button label="Save" press="{!c.createEvent}"/> </aura:component>Here is my JS Controller:
({ createEvent : function(component, event, helper) { // Validate form fields // Pass form data to a helper function var newEvent = component.get("v.newEvent"); helper.createEvent(component, newEvent); } })
Here is my Helper:
({ createEvent: function(component, event) { //Save the event and update the view this.upsertEvent(component, event, function(a) { var events = component.get("v.events"); events.push(a.getReturnValue()); component.set("v.events", events); }); }, upsertEvent : function(component, event, callback) { var action = component.get("c.saveEvent"); action.setParams({ 'event': event }); if (callback) { action.setCallback(this, callback); } $A.enqueueAction(action); } })Here is my Apex Controller:
public with sharing class EventController { @AuraEnabled public static List<Event> getEvents() { String runningUser = UserInfo.getUserId(); List<Event> events = Database.query( 'SELECT Id, Subject, WhoId, WhatId, EndDateTime, StartDateTime, Matter_Type__c, Color_Code__c, Type, Event_Type__c, OwnerId FROM Event WHERE OwnerId = :runningUser AND (StartDateTime = LAST_N_DAYS:45 OR StartDateTime = NEXT_N_DAYS:45)'); //Add isAccessible() check return events; } @AuraEnabled // Retrieve all primary contacts public static List<Event> getConsult() { List<Event> consultEvents = [SELECT Id, Subject, WhoId, WhatId, EndDateTime, StartDateTime, ActivityDate, OwnerId, Type FROM Event WHERE Event_Type__c = 'Consult' AND OwnerId = '005j000000BRyZ1']; //Add isAccessible() check return consultEvents; } @AuraEnabled public static Event saveEvent(Event event) { // Perform isUpdateable() check here upsert event; return event; } }The extra code in the controller is for another part of the app. It looks like the data is being passed to the Apex controller from the component and that the Apex controller is set up the same way as the example.
Any ideas on how to troubleshoot would be appreciated.
- Michael Friedman 7
- October 12, 2016
- Like
- 0