I'm building a 3 step wizard for feedback in visual force where the user is expected to fill up a form on each step of the page. I'm planning to use one controller for navigation and 3 visual force pages to handle the input and output fields .Here are things i would need some help.A user can fill the form say 2 steps and abandon and come again later and fill up the form. Has any body done this and if so can you share code snippets or best approach? How do we do this? Any code reference or articles with real examples would really help in this regard?. Thanks Joseph
-
Unless you allow them to save at each step along the way, or save their steps in a cookie, they won't be able to come back when they log-in later as the view state will have been lost in the controller.– crmprogdevCommented Aug 29, 2015 at 15:00
-
There's some pretty clever solutions, really, and it's not that hard to accomplish.– sfdcfox ♦Commented Aug 29, 2015 at 16:08
1 Answer
A basic solution for this involves the use of the Web Storage API, which will be necessarily complex (but possible), with some effort.
First, you'll need an actionMethod on each page of the wizard that allows the script to set values into the view state. This is necessary because you can't just save the view state directly; Bad Things happen if you try.
Second, you'll want to set up "on select" or "on change" events on every element you wish to save. You can use onchange and onselect attributes on managed elements (elements starting with apex:), but a generic document-level change handler will suffice for non-salesforce-specific field types (e.g. you will need to handle Lookup Fields in a special manner).
Third, you'll want an "on load" event handler so the actionMethod from the first step can be called to restore the elements back into the view state when the page first loads.
Putting it all together, you'll end up with something like this:
<apex:page controller="XYZ">
<script>
function onload() {
var oldValues = [], index = 0, key, value;
while(index < localStorage.length) {
key = localStorage.key(index++);
value = localStorage.get(key);
if(key.match(/myForm#.+/)) {
oldValues.push({key: key.split(/#/)[1], value: value});
}
}
restoreValues(oldValues);
}
window.addEventListener('load', onload, true);
</script>
...
<apex:form id="form">
<apex:actionFunction name="restoreValues" action="{!loadValuesToState}" reRender="form" />
<apex:param name="oldValues" value="" />
</apex:actionFunction>
...
<apex:inputText value="{!someVar}" onchange="this.value? localStorage.setItem('myForm#someVar', this.value): localStorage.removeItem('myForm#someVar')" />
...
</apex:form>
Then, in your controller:
public class KeyPair { String key, value }
public void loadValuesToState(KeyPair[] values) {
for(KeyPair[] value: values) {
if(value.key=='someVar') {
someVar = value.value;
}
...
}
There are "easier" ways of doing this, but most of them aren't very IE8 compatible, meaning you'd want to use jQuery if you expect IE8 will still be a problem. The problem will start when you need to start saving lookup fields (you need to store the _lkid value instead of the text value), multi-selects, and other salesforce-specific input types. The generic types, including regular text fields, long text fields, and select lists are easier to handle.
You'll probably also want to include a means of clearing the form once the wizard is done or if the user chooses to clear out the data. Note that I use a sort of "namespace" convention so you can have multiple forms use this technique without clobbering each other. This is important, because localStorage works at the domain level (e.g. all Visualforce pages will see each other's data).
This solution works even with no Internet connectivity, meaning you can guarantee that your user's data will survive the page failing to load due to intermittent issues, etc. Of course, you could implement a server-side solution as well; simply save their data periodically with an actionPoller set on the page that calls a function to save their data. This introduces the need for Internet connectivity, but allows them to resume their work on another browser/computer/device.