Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Building multi-page data entry
Controllers
Beyond Oz What to do when a simple Wizard is not enough
Stuart Greenberg, Oppen...
All about OppenheimerFunds, Inc.
Since the original Oppenheimer fund was first offered to the public in 1959, OppenheimerF...
Who’s who and what’s what
Stuart Greenberg
▪
▪
▪
▪

Professional programmer since 1975
Past Senior Programmer, PC Magazine...
Single vs. wizard vs. multi-page data entry
Single page
▪ Enter data / click save
Single vs. wizard vs. multi-page data entry
Wizard
▪ Enter data for step 1 / click next
▪ Enter data for step 2 / click ne...
Single vs. wizard vs. multi-page data entry
Multi-page
▪ Enter data on main page / click option
▪ Select option / Enter da...
The problem
▪ Break the limit of one Contact/Lead and/or one other object
attached to Events and Tasks (Multi-Who / Multi-...
The solution
▪ Custom object (ActivitySidecar) connected to Events and
Tasks using the WhatId
▪ Selection pages for all as...
Object structure
Overall structure
Controllers must be the
same across pages.

Classes instantiated as needed.

Interfaces allow
polymorphi...
DEMO
Gottas
Wachagottadew…
▪ Selections must be queued
▪ All queued data must be saved at the same time
▪ Page code must be set...
Selectable Object
public class OFI_SelectableObject {
public Boolean isSelected {set;get;}
public Boolean isEnabled {set;g...
Queueing selections
// Lists Selectable Objects of the related objects
// The tag property is used to indicate:
// an exis...
Selecting items
public PageReference selectItems() {
Integer i;
for (OFI_SelectableObject record: recordsToDisplay) {
if (...
Saving
try {
upsert evt;
} catch (DMLException e) {
ApexPages.addMessage(new
ApexPages.Message(ApexPages.SEVERITY.ERROR,
e...
Page code
Event Edit Page
<apex:page controller="ActivityEditPage2Controller" extensions="ActivityObjectSelController,VFFi...
Force instantiation on new session
You need to use the following when you wish to start a new
multi-page session:
PageRefe...
Gotchas
Gotchasgonnagetcha…
You can’t leave the page
The view state is maintained as long as the user doesn’t
navigate to a page that has a different ...
Avoid the message on “Good” clicks
For example, the following was added to the Page Block Buttons:
<apex:pageBlockButtons ...
<script type="text/javascript">
var isExitMessageTurnedOn = true;
var showExitMessage = true;
var isChrome = false;
var is...
Be careful using classes
▪ Classes called from the controllers can be instantiated
multiple times.
▪ Be sure to set the va...
Example

Destroy Selectors after each access
Of a selection page.
Return URLs
▪ Do not use the Return URL to go back to the initial page.
▪ Use the URL of the page itself.
▪ For example:
/...
Fugetaboutits
Patient: Doc, it hurts when I do this.
Doctor: Don’t do that.
The View State size
▪ The View State is the data that is held between pages.
▪ Up to 135K of data.
▪ An exception is throw...
Time outs
▪ Sessions sitting too long can be timed out and data lost.
▪ Use multi-page data entry only for quick tasks.
Alternatives
Use multi-page data entry when you really have to
Here are some alternatives:
▪ One page with hidden or colla...
Conclusion
▪ Multi-page data entry is possible with the proper care
▪ Use multi-page data entry once you’ve exhausted more...
Contact info and links
Contact me at:
▪ Twitter: @Stu_GuiGumdrops
▪ Blog: http://www.guigumdrops.com

Useful links:
▪ View...
Stuart Greenberg
OppenheimerFunds, Inc.,
Technical Lead
@Stu_GuiGumdrops
Creating Multi-Page Data Entry Controllers
Upcoming SlideShare
Loading in …5
×

Creating Multi-Page Data Entry Controllers

2,708 views

Published on

You've built a sample wizard with Visualforce, but what if your business requirements are more complex: saving across multiple objects, including Tasks and Events? Join us to learn how one customer solved this with a custom framework, using as few Apex controllers as possible, and dividing code classes into reusable modules.

  • Login to see the comments

Creating Multi-Page Data Entry Controllers

  1. 1. Building multi-page data entry Controllers Beyond Oz What to do when a simple Wizard is not enough Stuart Greenberg, OppenheimerFunds, Inc., Technical Lead @Stu_GuiGumdrops
  2. 2. All about OppenheimerFunds, Inc. Since the original Oppenheimer fund was first offered to the public in 1959, OppenheimerFunds, Inc. (OFI) has grown into one of the largest and most reputable investment management firms in Click to Today, a subsidiary of Massachusetts Mutual Life Insurance Company the country. add brief company overview here. Lorem ipsum (MassMutual), OFI and its subsidiaries adipiscing elit. Sed lectusservices to individuals, dolor sit amet, consectetur offer a broad array of products and tortor, institutional investors and corporations worldwide. OFI provides advisory services to the Oppenheimer mutual funds and OFI Global Asset Management provides services to institutional pulvinar sit amet blandit ac, bibendum vitae sapien. clients. OFI, including subsidiaries, managed more than $222 billion in assets for more than 12 million shareholder accounts, including sub-accounts, as of September 30, 2013. ▪ Click to add implementation highlights; no more than four For more than 50 years, OFI has embraced an investment culture that has produced results, is sustainable, and reflects its commitment to being effective stewards of capital. A high conviction ▪ Click to add implementation highlights; no more than four. Lorem asset manager, OFI has a history of providing innovative investment strategies to its investors. Fouripsum dolor sit amet, consecteturinvestment culture: active management can deliver core beliefs lie at the heart of the OFI adipiscing elit. better outcomes, independent investment boutiques lead to better ideas, a global perspective is critical, and knowing the difference between risk & no more than four ▪ Click to add implementation highlights; risky. OFI’s investment professionals are a collection of distinct, yet collaborative, teams built to enable ▪ Click to add implementation highlights; no more than four a free exchange of ideas and to uncover opportunity wherever it lies; even where others see a disparate set of facts, events or trends. OFI is redefining what the world can expect from an asset manager, and stands united on its mission to turn its unconventional wisdom into value for investors.
  3. 3. Who’s who and what’s what Stuart Greenberg ▪ ▪ ▪ ▪ Professional programmer since 1975 Past Senior Programmer, PC Magazine Labs Currently Tech Lead, OppenheimerFunds, Inc. Pennsylvania Railroad engineer And you? ▪ Visualforce developer? ▪ Written wizards or multi-page data entry? ▪ It’s late, all the other sessions were full and I just wanted to sit down?
  4. 4. Single vs. wizard vs. multi-page data entry Single page ▪ Enter data / click save
  5. 5. Single vs. wizard vs. multi-page data entry Wizard ▪ Enter data for step 1 / click next ▪ Enter data for step 2 / click next ▪ Etc.
  6. 6. Single vs. wizard vs. multi-page data entry Multi-page ▪ Enter data on main page / click option ▪ Select option / Enter data on new page / click return ▪ Select option / Enter data on another page / click return ▪ Click save
  7. 7. The problem ▪ Break the limit of one Contact/Lead and/or one other object attached to Events and Tasks (Multi-Who / Multi-What) ▪ Allow users to select objects in any order and skip selection of objects they don’t want ▪ Do not require the saving of Events and Tasks prior to selecting objects
  8. 8. The solution ▪ Custom object (ActivitySidecar) connected to Events and Tasks using the WhatId ▪ Selection pages for all associated objects ▪ Multi-page data entry to keep all data in memory and save at the end
  9. 9. Object structure
  10. 10. Overall structure Controllers must be the same across pages. Classes instantiated as needed. Interfaces allow polymorphic functionality
  11. 11. DEMO
  12. 12. Gottas Wachagottadew… ▪ Selections must be queued ▪ All queued data must be saved at the same time ▪ Page code must be setup correctly
  13. 13. Selectable Object public class OFI_SelectableObject { public Boolean isSelected {set;get;} public Boolean isEnabled {set;get;} public Boolean isInactive {set;get;} public Boolean isPrimary {set;get;} public String tag {set;get;} public Object obj {set;get;}
  14. 14. Queueing selections // Lists Selectable Objects of the related objects // The tag property is used to indicate: // an existing object (tag = '') // an object to be added (tag = 'A') // an object to be deleted (tag = 'D') public List<OFI_SelectableObject> selProducts {get;set;} public List<OFI_SelectableObject> selContacts {get;set;} public List<OFI_SelectableObject> selFirms {get;set;} public List<OFI_SelectableObject> selUsers {get;set;} public List<OFI_SelectableObject> selFinancialAccounts {get;set;} public List<OFI_SelectableObject> selOpportunities {get;set;} public List<OFI_SelectableObject> selCampaigns {get;set;} public List<OFI_SelectableObject> selCases {get;set;}
  15. 15. Selecting items public PageReference selectItems() { Integer i; for (OFI_SelectableObject record: recordsToDisplay) { if (record.isSelected) { if (!existingContactIds.contains(record.getContact().Id)) { // Not an existing selection for (i = 0; i < currentSelections.size(); i++) { // Check for undelete if (currentSelections[i].getActivityContact().Contact__c == record.getContact().Id && currentSelections[i].tag == 'D') { currentSelections[i].tag = ''; break; } } if (i == currentSelections.size()) { // Add new selection Activity_Contact__c actContact = new Activity_Contact__c(); // Set the Contact Id and Object. The Sidecar will be set when the Activity is saved. actContact.Contact__c = record.getContact().Id; actContact.Contact__r = record.getContact(); OFI_SelectableObject selObj = new OFI_SelectableObject(actContact); selObj.Tag = 'A'; currentSelections.add(selObj); } existingContactIds.add(record.getContact().Id); } } } return null; } // Add to existing Ids to enable checkmark
  16. 16. Saving try { upsert evt; } catch (DMLException e) { ApexPages.addMessage(new ApexPages.Message(ApexPages.SEVERITY.ERROR, e.getLineNumber() + e.getMessage())); return false; } If (sidecarId == null) { Activity_Sidecar__c sidecar = [SELECT Id FROM Activity_sidecar__c WHERE Activity_Id__c = :evt.Id LIMIT 1]; evt.WhatId = sidecar.Id; } // Add / Delete Products List<Activity_Product__c> delProds = new List<Activity_Product__c>(); List<Activity_Product__c> addProds = new List<Activity_Product__c>(); for (OFI_SelectableObject o : sidecarEditor.selProducts) { if (o.tag == 'D') { delProds.add(o.getActivityProduct } else { if (o.tag == 'A') { o.getActivityProduct().Activity_Sidecar__c = evt.WhatId; addProds.add(o.getActivityProduct()); } } } if (delProds.size() > 0) { delete(delProds); } if (addProds.size() > 0) { insert(addProds); }
  17. 17. Page code Event Edit Page <apex:page controller="ActivityEditPage2Controller" extensions="ActivityObjectSelController,VFFileUpload2" title="Calendar Event Edit"> Task Edit Page <apex:page controller="ActivityEditPage2Controller" extensions="ActivityObjectSelController,VFFileUpload2" title="Calendar Task Edit"> Selection Page <apex:page controller="ActivityEditPage2Controller" extensions="ActivityObjectSelController,VFFileUpload2" action="{!initObjectSelector}" title="Activity Contact Selection"> ▪ All controllers must be the same to keep their constructors from being called when a new page is opened. ▪ An Action must be added if any initialization is necessary when the page opens.
  18. 18. Force instantiation on new session You need to use the following when you wish to start a new multi-page session: PageReference page = new PageReference('/apex/TaskEditPage'); page.setRedirect(true);
  19. 19. Gotchas Gotchasgonnagetcha…
  20. 20. You can’t leave the page The view state is maintained as long as the user doesn’t navigate to a page that has a different set of controllers. The solution: Javascript
  21. 21. Avoid the message on “Good” clicks For example, the following was added to the Page Block Buttons: <apex:pageBlockButtons location="top" > <apex:commandButton value="Select and Return" action="{!SelectAndReturn}" onclick="setShowExitMessage(false);"/> <apex:commandButton value="Select and Add More" action="{!SelectItems}" onclick="setShowExitMessage(false);" rerender="thePage"/> <apex:commandButton value="Return" action="{!cancelSelection}" onclick="setShowExitMessage(false);"/> </apex:pageBlockButtons>
  22. 22. <script type="text/javascript"> var isExitMessageTurnedOn = true; var showExitMessage = true; var isChrome = false; var isSafari = false; var ua = navigator.userAgent.toLowerCase(); if (ua.indexOf('safari') != -1){ if(ua.indexOf('chrome') > -1){ isChrome = true; } else { isSafari = true; } } function setShowExitMessage(val) { showExitMessage = val; } function isJavascriptElement() { if (isChrome || isSafari) return false;
  23. 23. Be careful using classes ▪ Classes called from the controllers can be instantiated multiple times. ▪ Be sure to set the variables using the classes to null when finished.
  24. 24. Example Destroy Selectors after each access Of a selection page.
  25. 25. Return URLs ▪ Do not use the Return URL to go back to the initial page. ▪ Use the URL of the page itself. ▪ For example: // Cancel selection and return to the previous page. public pageReference cancelSelection() { destroySelector(); if (mainController.isTask) { return page.TaskEditPage2; } else { return page.EventEditPage2; } }
  26. 26. Fugetaboutits Patient: Doc, it hurts when I do this. Doctor: Don’t do that.
  27. 27. The View State size ▪ The View State is the data that is held between pages. ▪ Up to 135K of data. ▪ An exception is thrown if the limit is exceeded. ▪ Cannot hold attachments, for example.
  28. 28. Time outs ▪ Sessions sitting too long can be timed out and data lost. ▪ Use multi-page data entry only for quick tasks.
  29. 29. Alternatives Use multi-page data entry when you really have to Here are some alternatives: ▪ One page with hidden or collapsible sections ▪ A wizard flow based on initial selections ▪ Visual Workflow ▪ Dynamically generated search and select components
  30. 30. Conclusion ▪ Multi-page data entry is possible with the proper care ▪ Use multi-page data entry once you’ve exhausted more mainstream options ▪ Nothing is impossible… Impossible just takes a bit longer
  31. 31. Contact info and links Contact me at: ▪ Twitter: @Stu_GuiGumdrops ▪ Blog: http://www.guigumdrops.com Useful links: ▪ View State: http://wiki.developerforce.com/page/An_Introduction_to_Visualforce_View_State ▪ Visualforce and Visual Workflow: http://wiki.developerforce.com/page/User_Interface
  32. 32. Stuart Greenberg OppenheimerFunds, Inc., Technical Lead @Stu_GuiGumdrops

×