multi-page form and "back" button

W

William Gill

I previously posted in a PHP group to see if any JS or non JS options
exist, but seems like JS is still the best approach.

I am working on a form that will traverse many pages (lots of context
and a few inputs on each page). My concern is the user navigating back
and forth between pages w/o losing data (i.e. via the back button).

As far as I can tell, I need to integrate ECMA script, XMLHttpRequest,
and session variables, triggered by events like onLoad and onUnload.

Or I could just use submit() in lieu of AJAX, as long as I send form
field updates to the server however the page is exited.


Any suggestions?
 
D

Dr.Kral

I am working on a form that will traverse many pages (lots of context
and a few inputs on each page). My concern is the user navigating back
and forth between pages w/o losing data (i.e. via the back button).
Any suggestions?
Not knowing all the issues, I'll blindly mention four ideas.

1- Have one big page that the user just scrolls through. Although it might
take a bit to load, you have to d/l it all anyway.

2- Same as #1 but display only one section at a time. Could look a bit
neater than #1.

3- Set up a frame to hold the form and put the content in the other part of
the screen.

4.- If you can count on html5 support, then save all the fill-in in
localStorage and reset them on every reload. Equivalently, do the same
with a cookie. Use session storage/cookie unless you want recovery after
disconnect.

True you can combine the data in the server but then you add a lot of
communication delays.
 
W

William Gill

Not knowing all the issues, ...

Understood, but let's, just for once, assume that the OP (me) has made
an attempt to distill them down to a manageable number for focus in
order to eliminate the need for verbose postings such as this one.

Let's also stipulate that the OP (again me) doesn't always make things
crystal clear in the distillation. Let me try to clarify my query.

Without going into a lot on non JS, non HTML, and non web detail, the
questionnaire in it's existing written form is very long, and has
certain contract law type requirements (regarding "fine print",
relationships in font characteristics between different sections of the
document, etc.)

So let's assume I have good reason to use forms that I, or anyone else
might not otherwise prefer.

Now having looked at things from my client's, and their legal
department's perspective, I am trying to look at things from a user
perspective, and from the knowledge that the user won't always do what I
ask or expect. I am trying to take this 14 written page document, some
pages with only two or three completion fields, and make it a usable web
application. That means I have to guard against both confusion, and
loss of data if and when the user navigates around the document.

I assume I will have to have a solution that involves client side and
server side technologies. I stipulate that the user has only two
choices: 1) Print, complete, and mail a pdf version, or 2) enable
scripting in their browser. The third option (my preference), a
fill-able pdf was vetoed by the client.

So, all this having been said, we begin with numerous HTML forms
containing submit buttons labeled "back" and "next".

Knowing users, as I do, I realize they will not always navigate using
these "back" and "next" submit buttons. Realizing also that the HTML
DOM triggers various events that may be captured using ECMAScript,
knowing that browser support of these events is inconsistent, I turned
first to a PHP forum because PHP will be the server technology, but
which client solution was still under consideration. After some brief
discussion there I realized (confirmed actually) I should focus on
JavaScript for the client (browser) technology. So here I am.

That all having been said, I am asking the more experienced JS
aficionados to offer suggestions for the case where, for example, the
user fills in 3 of 5 fields on a page, then pages back through any means
other the previously mentioned submit button labeled "back."

I have considered using XMLHttpRequest in concert with onblur() (though
I believe my initial test indicated "back" sometimes circumvents onblur)
or simply using submit() in conjunction with something like onunload(),
but defer to the experience of the members of this NG for suggestions
and caveats.


1- Have one big page that the user just scrolls through. Although it might
take a bit to load, you have to d/l it all anyway.
Neither desirable or practical.
2- Same as #1 but display only one section at a time. Could look a bit
neater than #1.
I am actually considering this approach, but this is a secondary issue.
3- Set up a frame to hold the form and put the content in the other part of
the screen.
Neither desirable or practical, and I'm not a frames fan.
4.- If you can count on html5 support, then save all the fill-in in
localStorage and reset them on every reload. Equivalently, do the same
with a cookie. Use session storage/cookie unless you want recovery after
disconnect.
Not comfortable with the level of HTML5 support at this time, and not
sure cookies are practical here.
True you can combine the data in the server but then you add a lot of
communication delays.
In this instance communication delay is measured against snail mail.<g>
 
E

Elegie

On 29/06/2011 20:06, William Gill wrote :

Hello William,
I previously posted in a PHP group to see if any JS or non JS options
exist, but seems like JS is still the best approach.
I am working on a form that will traverse many pages (lots of context
and a few inputs on each page). My concern is the user navigating back
and forth between pages w/o losing data (i.e. via the back button).

Web clients, and especially clients targeted to the Internet, are mostly
uncontrolled environments. The technologies that they embed are various
and inconsistent (more than 100 browsers families and versions, with
differences in their DOM/javascript support), scripts may even be
deactivated or modified at runtime (either by some skilled user, or by
some tier plugin).

Consequently, client scripting should only be a part of the presentation
layer, concerned with setting up a user-friendly graphical interface,
but nothing more. It may work statically (on user actions) or
dynamically (on client events), but whichever way, should remain
restricted to requesting or posting data to the server-side part of the
presentation layer (and of course, never to the domain layer), where the
data will be checked, transformed into commands then sent and processed
to the domain layer.

If you have some user workflow, then I can only recommend that you
implement it server-side. All users will have equal access to it, and
you will have a better control on security issues.

Server-side technologies all provide session-keeping mechanisms, some in
a basic way (just offering access to some Session object), some in an
advanced way (setting up conversational views, navigation rules). Build
several forms, have them POSTed in the regular way, and structure your
workflow mechanism there (form posts are simply workflow events).

Also, while I do not know PHP, there must be some PHP pattern for
dealing with workflows. If not, you could even design your own
(classical design patterns can help here).
As far as I can tell, I need to integrate ECMA script, XMLHttpRequest,
and session variables, triggered by events like onLoad and onUnload.

As you understand, I would strongly advise against it. Do not hesitate
to post back, however, if you want to discuss the matter further. If you
still want to stick to some client-based approach, I will try and give
you some ideas for doing so in the best way.

Kind regards,
Elegie.
 
W

William Gill

On 29/06/2011 20:06, William Gill wrote :

Hello William,



Web clients, and especially clients targeted to the Internet, are mostly
uncontrolled environments. The technologies that they embed are various
and inconsistent (more than 100 browsers families and versions, with
differences in their DOM/javascript support), scripts may even be
deactivated or modified at runtime (either by some skilled user, or by
some tier plugin).

Consequently, client scripting should only be a part of the presentation
layer, concerned with setting up a user-friendly graphical interface,
but nothing more. It may work statically (on user actions) or
dynamically (on client events), but whichever way, should remain
restricted to requesting or posting data to the server-side part of the
presentation layer (and of course, never to the domain layer), where the
data will be checked, transformed into commands then sent and processed
to the domain layer.

If you have some user workflow, then I can only recommend that you
implement it server-side. All users will have equal access to it, and
you will have a better control on security issues.

Server-side technologies all provide session-keeping mechanisms, some in
a basic way (just offering access to some Session object), some in an
advanced way (setting up conversational views, navigation rules). Build
several forms, have them POSTed in the regular way, and structure your
workflow mechanism there (form posts are simply workflow events).

Also, while I do not know PHP, there must be some PHP pattern for
dealing with workflows. If not, you could even design your own
(classical design patterns can help here).


As you understand, I would strongly advise against it. Do not hesitate
to post back, however, if you want to discuss the matter further. If you
still want to stick to some client-based approach, I will try and give
you some ideas for doing so in the best way.

Kind regards,
Elegie.
Server side, and session data retention is at the heart of the
application. My concern is simply minimizing the user circumnavigating
session updates, by bypassing the submit button (i.e. clicking back).

As for scripting being disabled in the user's browser, the option
presented to them is either enable it, or print; complete; and mail, a
pdf form.
 
E

Elegie

Server side, and session data retention is at the heart of the
application. My concern is simply minimizing the user circumnavigating
session updates, by bypassing the submit button (i.e. clicking back).

But this is a workflow, right? Either you want your user to follow a
straight path (and you ensure navigation rules on the server, studying
the referrer before accepting the data, redirecting when the page is not
appropriate), or you authorize him to press the "back" button, which in
this case simply means an update of the data previously submitted (in
other words: your workflow has circular references, which is not
uncommon at all).

I am sorry, but I am afraid I do not understand the problem: provided
the data are only used when the final step of the workflow has been
validated, then why not allow any update? The user may make genuine
errors, realize it after the submission of the step, and want to correct
it before moving on.

What do you envision for the client interface? The user has some fields
to fill in, then press a button, then has other fields to fill in, and
so forth until the last page?

If the transition between the steps imply some server-side processing
(i.e. there is some branching in the workflow), then I am afraid you
have no way around (you must do it server side).

If, on the other hand, there is no control in the transition (i.e. all
controls can be made in the final step), then you can load all fields on
a single page, and dynamically rearrange them client-side (building
sub-views, showing the active sub-view and hiding the others). The user
will not be able to use the "Back" button, and will still have the full
form if javascript is deactivated (or missing). In the end, you would
have only one form submission (which may be what you're really looking for).
As for scripting being disabled in the user's browser, the option
presented to them is either enable it, or print; complete; and mail, a
pdf form.

This is fine. Setting up a fallback is imperative, and you did it well.

Kind regards,
Elegie.
 
W

William Gill

But this is a workflow, right? Either you want your user to follow a
straight path (and you ensure navigation rules on the server, studying
the referrer before accepting the data, redirecting when the page is not
appropriate), or you authorize him to press the "back" button, which in
this case simply means an update of the data previously submitted (in
other words: your workflow has circular references, which is not
uncommon at all).

I am sorry, but I am afraid I do not understand the problem: provided
the data are only used when the final step of the workflow has been
validated, then why not allow any update? The user may make genuine
errors, realize it after the submission of the step, and want to correct
it before moving on.

What do you envision for the client interface? The user has some fields
to fill in, then press a button, then has other fields to fill in, and
so forth until the last page?

If the transition between the steps imply some server-side processing
(i.e. there is some branching in the workflow), then I am afraid you
have no way around (you must do it server side).

If, on the other hand, there is no control in the transition (i.e. all
controls can be made in the final step), then you can load all fields on
a single page, and dynamically rearrange them client-side (building
sub-views, showing the active sub-view and hiding the others). The user
will not be able to use the "Back" button, and will still have the full
form if javascript is deactivated (or missing). In the end, you would
have only one form submission (which may be what you're really looking
for).


This is fine. Setting up a fallback is imperative, and you did it well.

Kind regards,
Elegie.

"Authorize him", what's to stop any user from clicking the back button
any time at all?

One of us is not following, and I'm not sure if it's you or me.

Let me try again. Yes it's a workflow. Yes the user will be able to
edit any information on any page until the final submit is performed.
Yes server technology will keep track of the state of all fields until
final processing.

Now suppose a user is on page 10 (of 14), has answered 3 of the 5
questions on this page, but one of the questions makes them rethink a
previous answer. Here's where the problem occurs. Instead of clicking
one of the two submit buttons (the one labeled "back"), they use a
mechanism they are already familiar with: the browser back button. They
go back however many pages, change the answer, then return to where they
left off. Since they left page 10 without properly submitting it, the
three answers they had previously entered were never updated anywhere.
Some have implied that the answers may be retained in the browser cache,
but even that is unreliable. Anyway assuming the fields are empty and
all three empty fields appear on the user's browser they should see them
and reenter the information, but there is no guarantee they will notice
or refill them. to exacerbate the situation, if page 10 spans two or
three screens, the likelihood they will notice and correct things is
diminished. Either way, the user is annoyed because they have to do
anything over.

So to restate my concern is as simple, and inclusive a manner as
possible: Is there any way to force a submit() regardless of how the
page is exited?
 
T

Tim Streater

"Authorize him", what's to stop any user from clicking the back button
any time at all?

One of us is not following, and I'm not sure if it's you or me.

Let me try again. Yes it's a workflow. Yes the user will be able to
edit any information on any page until the final submit is performed.
Yes server technology will keep track of the state of all fields until
final processing.

Now suppose a user is on page 10 (of 14), has answered 3 of the 5
questions on this page, but one of the questions makes them rethink a
previous answer. Here's where the problem occurs. Instead of clicking
one of the two submit buttons (the one labeled "back"), they use a
mechanism they are already familiar with: the browser back button. They
go back however many pages, change the answer, then return to where they
left off. Since they left page 10 without properly submitting it, the
three answers they had previously entered were never updated anywhere.
Some have implied that the answers may be retained in the browser cache,
but even that is unreliable. Anyway assuming the fields are empty and
all three empty fields appear on the user's browser they should see them
and reenter the information, but there is no guarantee they will notice
or refill them. to exacerbate the situation, if page 10 spans two or
three screens, the likelihood they will notice and correct things is
diminished. Either way, the user is annoyed because they have to do
anything over.

So to restate my concern is as simple, and inclusive a manner as
possible: Is there any way to force a submit() regardless of how the
page is exited?

Why is ajax not being used for this situation? Then you can always be on
the same page, but in a different state depending what the user has
done. And if they click "Back" then they go to the page before this
whole data entering sequence.

When you buy something over the web, you very often need to go through a
series of steps, such as:

1) enter delivery details
2) enter special offer codes
3) enter card details
4) etc

At the top of the page I would have a series of small graphics that
label these steps, left to right, and each is a button, but each is only
live if you've already done that step. So you have to proceed
sequentially in order to make progress.

But, if you are in one a later step, this would allow you to click the
graphic for an earlier step, make some changes, and then click the
graphic for the step you were in - all with no data loss.

All this is doable with ajax and a bit of Javascript logic. As I said,
you're always on the same page, so you could use onunload if they hit
the "Back" button, which IIRC gives you the option to ask if they really
want to lose their data, and telling them how to get to an earlier step
if that's what they actually want.
 
W

William Gill

Why is ajax not being used for this situation? Then you can always be on
the same page, but in a different state depending what the user has
done. And if they click "Back" then they go to the page before this
whole data entering sequence.

When you buy something over the web, you very often need to go through a
series of steps, such as:

1) enter delivery details
2) enter special offer codes
3) enter card details
4) etc

At the top of the page I would have a series of small graphics that
label these steps, left to right, and each is a button, but each is only
live if you've already done that step. So you have to proceed
sequentially in order to make progress.

But, if you are in one a later step, this would allow you to click the
graphic for an earlier step, make some changes, and then click the
graphic for the step you were in - all with no data loss.

All this is doable with ajax and a bit of Javascript logic. As I said,
you're always on the same page, so you could use onunload if they hit
the "Back" button, which IIRC gives you the option to ask if they really
want to lose their data, and telling them how to get to an earlier step
if that's what they actually want.
Tim,

Ajax (XMLHttpRequest) was my first thought, and still is. My concern is
making it fire whenever the user leaves the page, unless you are
suggesting firing it on every onchange event.

I experimented with Ajax and the onblur event, but if I remember
correctly, some browsers didn't trigger an onblur event when a browser
"back" was executed (by whatever mechanism).

Simply put: What event can I rely on to trigger an update via an
XMLHttpRequest object?
 
D

Denis McMahon

[big form problem]

If you have multiple "div" elements and switch between document sections
by hiding and unhiding the relevant div elements (which will require
javascript but no client - server interaction or server side support)
could that be a solution?

You could also use onchange events on the data entry fields to trigger an
event that serialised the form data and stored it as a cookie, and test
for the presence of the cookie with a body onload event to re-populate
the form if they do navigate away and back again. However, if you do
that, might be a good idea to have the form's submit trigger a script to
destroy the cookie, otherwise the next person to load the form on the
computer might see the previous user's data.

Rgds

Denis McMahon
 
W

William Gill

All this is doable with ajax and a bit of Javascript logic. As I said,
you're always on the same page, so you could use onunload if they hit
the "Back" button, which IIRC gives you the option to ask if they really
want to lose their data, and telling them how to get to an earlier step
if that's what they actually want.
Reread your post. I missed a couple things. First the onbeforeunload
event is the one used to ask the user about losing their data, but
support is unreliable. Don't remember why I was led to believe the same
is true for the onunload event. I'll have to go back over all the
threads, and retest to see if that's true. If not I think I may be done.
 
E

Elegie

On 01/07/2011 23:44, William Gill wrote :

Hi,
One of us is not following, and I'm not sure if it's you or me.

It was me!
Now suppose a user is on page 10 (of 14), has answered 3 of the 5
questions on this page, but one of the questions makes them rethink a
previous answer. Here's where the problem occurs. Instead of clicking
one of the two submit buttons (the one labeled "back"), they use a
mechanism they are already familiar with: the browser back button. They
go back however many pages, change the answer, then return to where they
left off. Since they left page 10 without properly submitting it, the
three answers they had previously entered were never updated anywhere.
Some have implied that the answers may be retained in the browser cache,
but even that is unreliable. Anyway assuming the fields are empty and
all three empty fields appear on the user's browser they should see them
and reenter the information, but there is no guarantee they will notice
or refill them. to exacerbate the situation, if page 10 spans two or
three screens, the likelihood they will notice and correct things is
diminished. Either way, the user is annoyed because they have to do
anything over.

Thank you for your explanation. As Denis and Tim have suggested, you can
use many approaches.

The first approach uses client-side state keeping, with cookies. It is
simple to use, you can build a StateManager which loads all form data
when the page is loaded, and persists it each time a form field is changed.

The second approach uses server-side state keeping, with Ajax or other
techniques (see <URL:http://www.jibbering.com/faq/#runServerScript>).
Your StateManager lives on the server-side presentation layer, which is
fine as well.

Both approaches look fine to me. I can see a tiny usability risk with
the client-side state keeping, in that users, seeing data in the form,
could be led to believe that they have already submitted the data
(forgetting they did not), and continue the workflow without submitting
it. On the other hand, I can spot some performance issue with the
server-side state keeping: depending on which event you transmit your
data, many users filling in the form at the same time can quickly have
lots of requests generated.

I would slightly favor the server-side state keeping, but YMMV.
So to restate my concern is as simple, and inclusive a manner as
possible: Is there any way to force a submit() regardless of how the
page is exited?

The FAQ says it is difficult: <URL:
http://www.jibbering.com/faq/#sessionExpired>. The point is to identify
which event can be used to submit the data. "onunload", as explained by
the FAQ, may not be reliable. "onbeforeunload" is reliable but I do not
know if it is implemented consistently in modern browsers. Therefore,
what about using "onchange", for each field?

As an illustration, have a look at the following script (my personal
"Good Morning Javascript!" broadcast). It is built in two parts: a
StateManager definition, which you can insert as a regular script
include, and a StateManager initialization, which you have to position
into a SCRIPT element in the main page, either in a window.onload event,
or after the form you want to monitor.

The initialization part :
---
StateManager.init(document.forms[0]); // reference to the form
---


The main script:
---
var StateManager = (function() {

function QueryStringBuilder() {
this.parts = [];
}

QueryStringBuilder.prototype.add = (function (el) {
switch (el.type.toLowerCase()) {
case "text":
case "hidden":
case "textarea":
case "password":
this.parts.push(pair(el.name, el.value));
break;
case "checkbox":
case "radio":
if (el.checked) {
this.parts.push(pair(el.name, el.value || "true"));
}
break;
case "select":
case "select-multiple":
for (var ii=0; ii<el.options.length; ii++) {
if (el.options[ii].selected) {
var option = el.options[ii];
this.parts.push(
pair(el.name, option.value || option.text)
);
}
}
break;
}

function pair(name, value) {
return encodeURIComponent(name) +
":" +
encodeURIComponent(value);
}

});

QueryStringBuilder.prototype.getValue = (function (el) {
return this.parts.join("&");
});

function addListener(target, evt, listener) {
if (target[evt]) {
target[evt] = (function(oldListener) {
return (function() {
oldListener.apply(this, arguments);
return listener.apply(this, arguments);
});
})(target[evt]);
} else {
target[evt] = listener;
}
}

function persistData(form) {
var img = new Image();
var qs = new QueryStringBuilder();
var qs_value="";
for (var els=form.elements, ii=0; ii<els.length; ii++) {
qs.add(els[ii]);
}
qs_value = qs.getValue();
if (qs_value) {img.src="workflow?" + qs_value;}
}

function fieldListener(evt) {
persistData(this.form);
}

return ({
init : (function(form){
for (var els=form.elements, ii=0; ii<els.length; ii++) {
if (els[ii].type.toLowerCase() != "submit") {
addListener(els[ii], "onchange", fieldListener);
}
}
})
});
})() ;
 
T

Tim Streater

William Gill said:
Reread your post. I missed a couple things. First the onbeforeunload
event is the one used to ask the user about losing their data, but
support is unreliable. Don't remember why I was led to believe the same
is true for the onunload event. I'll have to go back over all the
threads, and retest to see if that's true. If not I think I may be done.

I suspect you're right, it is onbeforeunload.

I use it in my stuff, but not for the purpose I was suggesting in my
post (I use it to ensure I clean up if the user closes the window).
 
T

Tim Streater

William Gill said:
On 1/7/2011 6:12 PM, Tim Streater wrote:

[big snip]
Tim,

Ajax (XMLHttpRequest) was my first thought, and still is. My concern is
making it fire whenever the user leaves the page, unless you are
suggesting firing it on every onchange event.

I experimented with Ajax and the onblur event, but if I remember
correctly, some browsers didn't trigger an onblur event when a browser
"back" was executed (by whatever mechanism).

Simply put: What event can I rely on to trigger an update via an
XMLHttpRequest object?

I'm using onbeforeunload to ensure that I clean up (which involves
making an ajax request) if the user clicks the window close button. I do
however have the luxury of being able to code for just the one browser
(since I launch that browser from a PHP script).

Not sure what to do if the user force-quits the browser, or the OS
crashes, though.
 
E

Elegie

case "select":

.... should be :

case "select-one":

Sorry for the mistake. Also, the implementation provided is a bit
simplistic, as it does not handle dynamically new types of controls (no
default value provided).

Regards,
Elegie.
 
W

William Gill

The FAQ says it is difficult: <URL:
http://www.jibbering.com/faq/#sessionExpired>. The point is to identify
which event can be used to submit the data. "onunload", as explained by
the FAQ, may not be reliable. "onbeforeunload" is reliable but I do not
know if it is implemented consistently in modern browsers. Therefore,
what about using "onchange", for each field?
Server side state keeping is the given. I was just hoping, as a good
net citizen, I wouldn't have to litter the internet with transactions on
each keystroke as onchange would require, but unfortunately it seems to
be the most reliable event trigger for this.
 
E

Elegie

On 02/07/2011 21:13, William Gill wrote :

Hello William,
Server side state keeping is the given. I was just hoping, as a good net
citizen, I wouldn't have to litter the internet with transactions on
each keystroke as onchange would require, but unfortunately it seems to
be the most reliable event trigger for this.

There seems to be a misunderstanding here: change events will fire only
when the user has finished updating a field (i.e. the field has been
blurred and its value has changed), and not each time a key has been
pressed (see the script I have provided). Theoretically, change events
should be restricted to INPUT, SELECT and TEXTAREA elements, but I
believe they also work for other form controls.

<URL:http://www.w3.org/TR/DOM-Level-2-Events/events.html#Events-eventgroupings-htmlevents>

Do not hesitate to experiment with other event though, until you find
what fits your needs best.

<URL:http://www.w3.org/TR/DOM-Level-3-Events/#event-types-list>

Regards,
Elegie.
 
W

William Gill

There seems to be a misunderstanding here: change events will fire only
when the user has finished updating a field (i.e. the field has been
blurred and its value has changed), and not each time a key has been
pressed (see the script I have provided). Theoretically, change events
should be restricted to INPUT, SELECT and TEXTAREA elements, but I
believe they also work for other form controls.
There sure is some misunderstanding. Tests confirm you are right. I
could have sworn the last time I used onchange it fired on every change
(keystroke)? Must be confusing it w/some other language's change event.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,755
Messages
2,569,536
Members
45,013
Latest member
KatriceSwa

Latest Threads

Top