Back button clears form fields in wizard and plain forms

835 views
Skip to first unread message

Donny Nadolny

unread,
Nov 22, 2011, 8:34:52 PM11/22/11
to lif...@googlegroups.com
Hi,

I'm trying to make a 3 page wizard manually using plain forms, as an exercise to learn lift and so that I have more control over the form appearance. I've got it all working, the only problem I have is that when I use the browser back button from the 2nd page to the 1st page (or from the 3rd to the 2nd), all the fields in the form are cleared in the browser.

I've tried it out in Firefox 3.6 and the latest Chrome, both with my code and with the wizard demo at http://demo.liftweb.net/wiz2. Using the browser back button always clears the fields. I'm using lift 2.4-M5, and demo.liftweb.net says it's using 2.3.

I looked in to it with Firebug and the fields always get a new random GUID name, so the browser doesn't remember the value from the previous page.

My code looks mostly like the sample from http://simply.liftweb.net/index-4.1.html#toc-Section-4.1, you can reproduce it by running the example from https://github.com/dpp/simply_lift/tree/master/samples/forms, going to the page titled "Dumb Form", entering text, clicking submit, then clicking the browser back button. The expected result is that any text entered will be remembered, but instead it's empty.
The same thing happens at http://demo.liftweb.net/wiz2: enter some text, click next, click browser back, the text is gone.

How can I fix this so that fields get re-populated by the browser when the browser back button is used? I'd like do to this for the dumb form version, although I'm curious how it's done in the wizard version too if it's different than the plain form one.

Thanks,
Donny

Diego Medina

unread,
Nov 24, 2011, 10:43:14 PM11/24/11
to lif...@googlegroups.com
Hi,

One way would be to use SessionVar's to store the values of each of
your form fields, and on page request, you would load those values.
But the problem with this is that you can only have one browser window
open, if you have two, they would override each other.

If you need multiple tas to work, I think that using RequestVars with
a mix of snapshots[1] should do the trick, but I haven't tried that
before (very tempting though :) )

There is a way to make form fields use the same GUID, but this would
make your forms vulnerable to replay attacks, and I don't think you
would really want that

[1] http://blog.fmpwizard.com/54204619 (small gem title)

Hope that helps

Diego

> --
> Lift, the simply functional web framework: http://liftweb.net
> Code: http://github.com/lift
> Discussion: http://groups.google.com/group/liftweb
> Stuck? Help us help you:
> https://www.assembla.com/wiki/show/liftweb/Posting_example_code
>

--
Diego Medina
Web Developer
di...@fmpwizard.com
http://www.fmpwizard.com

David Pollak

unread,
Nov 28, 2011, 12:52:50 PM11/28/11
to lif...@googlegroups.com
The browsers changed back-button behavior.  Lift issues a series of See Other redirects that are supposed to make sure the URL that the back button points to restores the state of the Wizard to the "right" state.  Unfortunately, some browsers are going back more URLs than they are supposed to (or at least than they did when I originally wrote Wizard.)  Please open a ticket (http://ticket.liftweb.net you must be a watcher of the LiftWeb space on Assembla) referencing this thread and assign the ticket to me.  I'll figure out how to insert the correct interstitial pages so the back buttons behave correctly in Wizard.


--



--
Visi.Pro, Cloud Computing for the Rest of Us http://visi.pro
Lift, the simply functional web framework http://liftweb.net


Donny Nadolny

unread,
Nov 28, 2011, 9:29:49 PM11/28/11
to lif...@googlegroups.com
David: Created ticket https://www.assembla.com/spaces/liftweb/tickets/1154-browser-back-button-clears-fields-in-wizard

Diego: Thanks for the link. I've tried to get the "snapshot" pattern working, but I couldn't. What I've ended up with is something with similar benefits but implemented using request vars. I link to the page, eg "/signup" and if there is no request var, create a new holder for the information and redirect to the same page but with the request var set.
The end result is that you can go to the (manually created) wizard and fill in information, use browser back and forward buttons, and the fields in the browser never get cleared. You can even open multiple tabs and they don't interfere, as long as you don't do it by opening them by right clicking on the back button and opening it in a new tab. It's not perfect, but I'm willing to trade off problems with some corner cases in order to restore browser back button functionality.

For reference, here's some sample code:

class SignUpInfo {
  var firstName = ""
  var lastName = ""
  var email = ""
}

object CurrentSignUpInfo extends RequestVar[Box[SignUpInfo]](Empty)

object Signup {
  def step1 = {
    var info = CurrentSignUpInfo.get.getOrElse({ // ** this is the important part **
      val info = new SignUpInfo()
      S.redirectTo(S.uri, () => {CurrentSignUpInfo.set(Full(info))})
    })

    def process() {
      //do validation, match on errors, etc
      S.redirectTo("/signup2", () => {CurrentSignUpInfo.set(Full(info))})
    }

    "name=firstName" #> SHtml.text(info.firstName, info.firstName = _) &
    "name=lastName" #> SHtml.text(info.lastName, info.lastName = _) &
    "type=submit" #> SHtml.onSubmitUnit(process)
  }

  def step2 = {
    //... more code, get email address here
  }
}


You mentioned there was a way to make the form fields use the same GUID, but I can't find any information on how to do that. To me, that would be preferable to the default behavior of the browser losing any information they enter in to a form when they click back. In many cases it would be preferable to improve the user experience at the cost of replay attacks, because in many of the cases I'm thinking of for my application, replay attacks don't matter. Imagine an "advanced search" form where users fill in many fields and then do a search. Clicking back and having all information cleared would be extremely frustrating, and it's not at all necessary to defend against replay attacks. The same goes for the form I was making that prompted this email, a registration form. If you replay an unsuccessful registration you're just going to get the same errors, and if you replay a successful one you'll get an "account name already registered" error.

I'm really new to lift so feel free to tell me if this can't be done or if it's a bad idea, but: instead of renaming all fields to GUID names, could you instead keep their normal name but add a hidden field (maybe one hidden field per normal field) with a GUID name to do the binding to functions? It would store the name of the field it's for as well as the function it's bound to. Is this something that could be done without modifying the lift code itself, maybe by rewriting the response to add the fields, and hooking in to some sort of extension point for the GUID name mapping? This would make the request a bit larger, and form submissions would have to submit a bit more data, but it means that the back button *always* works by default (in terms of remembering the contents of fields), browser autofill works (when you click the email field on a website you've never been to before and it pops up your email address because it's name "email"), plugins to automatically fill out forms work, etc.

Donny

Naftoli Gugenheim

unread,
Nov 29, 2011, 9:05:01 PM11/29/11
to lif...@googlegroups.com
Personally I think it would be nice if GUIDs were optional. If a template has a name attribute, why not use that as the key in the function map?
The obvious problem is that the same input name could be used in different places in the webapp, causing unwanted overwriting of functions. Perhaps a solution would be, to somehow* include a hidden form input that identifies the page (unless there's an existing mechanism to know which page the submit request is coming from that's in place already), and make the function map key a composite of the page id and the input name.

* Perhaps all Lift-generated form elements (triggered by class="lift:MySnippet?format=

David Pollak

unread,
Nov 29, 2011, 11:50:15 PM11/29/11
to lif...@googlegroups.com
On Tue, Nov 29, 2011 at 6:05 PM, Naftoli Gugenheim <nafto...@gmail.com> wrote:
Personally I think it would be nice if GUIDs were optional. If a template has a name attribute, why not use that as the key in the function map?

That's just not possible.  The GUIDs have to be GUIDs... that's a core part of Lift.

The GUIDs are not the issue here, it's the place that the browser chooses to treat as the "previous" page... Chrome and newer versions of Firefox treat the "previous" page URL differently, and I have to test for that and make sure the right thing happens.

Naftoli Gugenheim

unread,
Nov 29, 2011, 11:53:47 PM11/29/11
to lif...@googlegroups.com
On Tue, Nov 29, 2011 at 11:50 PM, David Pollak <feeder.of...@gmail.com> wrote:


On Tue, Nov 29, 2011 at 6:05 PM, Naftoli Gugenheim <nafto...@gmail.com> wrote:
Personally I think it would be nice if GUIDs were optional. If a template has a name attribute, why not use that as the key in the function map?

That's just not possible.  The GUIDs have to be GUIDs... that's a core part of Lift.

The GUIDs are not the issue here, it's the place that the browser chooses to treat as the "previous" page... Chrome and newer versions of Firefox treat the "previous" page URL differently, and I have to test for that and make sure the right thing happens.
 
Right, it was tangential.
Let me put it in different words: What if the GUID had the form PAGEGUIID:name --- is it not possible to make Lift work that way (at least optionally)?

David Pollak

unread,
Nov 29, 2011, 11:56:53 PM11/29/11
to lif...@googlegroups.com
I don't think so.  
 

--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code

Donny Nadolny

unread,
Nov 30, 2011, 10:19:19 AM11/30/11
to lif...@googlegroups.com
On Tue, Nov 29, 2011 at 11:56 PM, David Pollak <feeder.of...@gmail.com> wrote:


On Tue, Nov 29, 2011 at 8:53 PM, Naftoli Gugenheim <nafto...@gmail.com> wrote:


On Tue, Nov 29, 2011 at 11:50 PM, David Pollak <feeder.of...@gmail.com> wrote:


On Tue, Nov 29, 2011 at 6:05 PM, Naftoli Gugenheim <nafto...@gmail.com> wrote:
Personally I think it would be nice if GUIDs were optional. If a template has a name attribute, why not use that as the key in the function map?

That's just not possible.  The GUIDs have to be GUIDs... that's a core part of Lift.

The GUIDs are not the issue here, it's the place that the browser chooses to treat as the "previous" page... Chrome and newer versions of Firefox treat the "previous" page URL differently, and I have to test for that and make sure the right thing happens.

Would the solution you have in mind also fix regular forms, eg ones made with Screen and with forms built by using SHtml.text, or would it only fix Wizard? If it would only fix Wizard I'm curious what your thoughts are on the idea of using a hidden field for each form element to hold the GUID so that the regular element maintains its name.
 

David Pollak

unread,
Nov 30, 2011, 10:29:24 AM11/30/11
to lif...@googlegroups.com
On Wed, Nov 30, 2011 at 7:19 AM, Donny Nadolny <donny....@gmail.com> wrote:


On Tue, Nov 29, 2011 at 11:56 PM, David Pollak <feeder.of...@gmail.com> wrote:


On Tue, Nov 29, 2011 at 8:53 PM, Naftoli Gugenheim <nafto...@gmail.com> wrote:


On Tue, Nov 29, 2011 at 11:50 PM, David Pollak <feeder.of...@gmail.com> wrote:


On Tue, Nov 29, 2011 at 6:05 PM, Naftoli Gugenheim <nafto...@gmail.com> wrote:
Personally I think it would be nice if GUIDs were optional. If a template has a name attribute, why not use that as the key in the function map?

That's just not possible.  The GUIDs have to be GUIDs... that's a core part of Lift.

The GUIDs are not the issue here, it's the place that the browser chooses to treat as the "previous" page... Chrome and newer versions of Firefox treat the "previous" page URL differently, and I have to test for that and make sure the right thing happens.

Would the solution you have in mind also fix regular forms, eg ones made with Screen and with forms built by using SHtml.text, or would it only fix Wizard? If it would only fix Wizard I'm curious what your thoughts are on the idea of using a hidden field for each form element to hold the GUID so that the regular element maintains its name.

Lift's GUID stuff is a core part of Lift and is not going to change.

Diego Medina

unread,
Dec 1, 2011, 2:03:27 PM12/1/11
to lif...@googlegroups.com
On Mon, Nov 28, 2011 at 9:29 PM, Donny Nadolny <donny....@gmail.com> wrote:
> Diego: Thanks for the link. I've tried to get the "snapshot" pattern
> working, but I couldn't. What I've ended up with is something with similar
> benefits but implemented using request vars. I link to the page, eg
> "/signup" and if there is no request var, create a new holder for the
> information and redirect to the same page but with the request var set.
> The end result is that you can go to the (manually created) wizard and fill
> in information, use browser back and forward buttons, and the fields in the
> browser never get cleared. You can even open multiple tabs and they don't
> interfere, as long as you don't do it by opening them by right clicking on
> the back button and opening it in a new tab. It's not perfect, but I'm
> willing to trade off problems with some corner cases in order to restore
> browser back button functionality.
>

> You mentioned there was a way to make the form fields use the same GUID, but
> I can't find any information on how to do that. To me, that would be

I looked and it was the other way around, on test mode, the GUID are
stable (well, for the most part unless you make some changes to your
forms). SO while in test mode, you can surround your fields with a
method that would force random GUID even in test mode. Sorry for the
false hope.

I am glad you got something working for now though and that you shared
it on the list.

Regards,

Diego

--

Naftoli Gugenheim

unread,
Dec 2, 2011, 3:23:26 AM12/2/11
to lif...@googlegroups.com
 
Lift's GUID stuff is a core part of Lift and is not going to change.
 

It won't change in any respect, ever, no matter what?


David Pollak

unread,
Dec 2, 2011, 8:48:38 AM12/2/11
to lif...@googlegroups.com
On Fri, Dec 2, 2011 at 12:23 AM, Naftoli Gugenheim <nafto...@gmail.com> wrote:
 
Lift's GUID stuff is a core part of Lift and is not going to change.
 

It won't change in any respect, ever, no matter what?

It can't.  There are so many parts of Lift that depend on the GUID, how the GUID is constructed (including the fact that it's a monotonically increasing value), that trying another scheme will potentially break a lot of code.  It would mean a complete re-write of all of SHtml, Screen, Wizard, Comet, and more.  Trying to change from GUIDs would mean writing a new web framework.
 


--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code

Naftoli Gugenheim

unread,
Dec 5, 2011, 12:43:57 AM12/5/11
to lif...@googlegroups.com
Ah, I see, thanks. I appreciate your taking the time to explain. It's very unfortunate that things have such a monolithic design. :(



On Fri, Dec 2, 2011 at 8:48 AM, David Pollak <feeder.of...@gmail.com> wrote:
On Fri, Dec 2, 2011 at 12:23 AM, Naftoli Gugenheim <nafto...@gmail.com> wrote:
 
Lift's GUID stuff is a core part of Lift and is not going to change.
 

It won't change in any respect, ever, no matter what?

It can't.  There are so many parts of Lift that depend on the GUID, how the GUD is constructed (including the fact that it's a monotonically increasing value), that trying another scheme will potentially break a lot of code.  It would mean a complete re-write of all of SHtml, Screen, Wizard, Comet, and more.  Trying to change from GUIDs would mean writing a new web framework.
 


--
Lift, the simply functional web framework: http://liftweb.net
Code: http://github.com/lift
Discussion: http://groups.google.com/group/liftweb
Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code

Tobias Pfeiffer

unread,
May 17, 2012, 6:16:02 PM5/17/12
to lif...@googlegroups.com
Hi,

Am Montag, 28. November 2011, 18:52 schrieb David Pollak:
> The browsers changed back-button behavior. Lift issues a series of
> See Other redirects that are supposed to make sure the URL that the
> back button points to restores the state of the Wizard to the
> "right" state. Unfortunately, some browsers are going back more URLs
> than they are supposed to (or at least than they did when I
> originally wrote Wizard.) Please open a ticket
> (http://ticket.liftweb.net you must be a watcher of the LiftWeb
> space on Assembla) referencing this thread and assign the ticket to
> me. I'll figure out how to insert the correct interstitial pages so
> the back buttons behave correctly in Wizard.

I've just stumbled into the same issue. Are there any news on that
ticket (#1154)?

Tobias

Diego Medina

unread,
May 18, 2012, 12:12:10 AM5/18/12
to lif...@googlegroups.com
> I've just stumbled into the same issue. Are there any news on that
> ticket (#1154)?

Fresh out of the oven I have a working example that allows you to go
back pages, and the form fields maintain the data you entered on them,
and it also gives you actual back buttons on the UI.
https://github.com/fmpwizard/lift-custom-wizard/tree/stateful

It does not use wizard, it uses StatefulSnippet, there is one minor
issue, which I'll fix this coming week, the issue is that the first
screen does not support the back button, but the 2,3 and 4th page do
(so the fix should not be that much).

Anyway, I hope it helps. This is a follow up example to this other
blog post I wrote:

http://blog.fmpwizard.com/scala-lift-custom-wizard
Once I have this new example working without any issues, I'll write a
blog explaining what I did, but feel free to ask any questions if you
decide to go this route.

Cheers,

Diego

>
> Tobias
>
> --
> Lift, the simply functional web framework: http://liftweb.net
> Code: http://github.com/lift
> Discussion: http://groups.google.com/group/liftweb
> Stuck? Help us help you: https://www.assembla.com/wiki/show/liftweb/Posting_example_code



--
Diego Medina
Lift/Scala Developer
di...@fmpwizard.com
http://www.fmpwizard.com

David Pollak

unread,
May 18, 2012, 11:11:00 AM5/18/12
to lif...@googlegroups.com
Any chance you can work on the Wizard code rather than rolling your own?
Visi.Pro, Cloud Computing for the Rest of Us http://visi.pro
Lift, the simply functional web framework http://liftweb.net

Diego Medina

unread,
May 18, 2012, 12:30:25 PM5/18/12
to lif...@googlegroups.com
On Fri, May 18, 2012 at 11:11 AM, David Pollak
<feeder.of...@gmail.com> wrote:
> Any chance you can work on the Wizard code rather than rolling your own?
>

Sure, I'll take a look at it.
The one I wrote was mostly because at the time I needed more
flexibility with form fields, which the new version of wizard will
adress I think. But I wasn;t too happy having one RequestVar plus one
variable for each "data unit" I needed. Then I found StatefulSnippet
and I was meaning to write about it for a long time :)

Regards,

Diego

Christopher Poile

unread,
May 18, 2012, 1:07:28 PM5/18/12
to lif...@googlegroups.com
Diego,

Thanks for the work! I cloned it and tried it out, but I think it might not be working correctly (or I misunderstand its purpose). For example, I put my name in sidebar First, press Next, and the name is shown on sidebar Second's page. Then click sidebar Third, and name disappears. Click sidebar Second, name is not there. I guess you need to use the next and back buttons instead of the left tab bar? But even entering a name, pressing Next, and then pressing UI's back button, it erases the name I had entered (instead of placing it in the input field to be edited or saved again without change).

Hope that helps...?  :)

Chris.

Diego Medina

unread,
May 18, 2012, 1:24:34 PM5/18/12
to lif...@googlegroups.com
Hi,

Right, I should hide the second, third and final links, the idea is
you click on first on the left side, then enter your name, click next,
enter your last name, click next, now you can use the browser back and
you will see your first name and the input for last name with your
last name, if you go back one more time, that will not work, and I
need to see why :).


Does that make sense?

Diego

Christopher Poile

unread,
May 18, 2012, 3:19:21 PM5/18/12
to lif...@googlegroups.com
Yes, makes sense. I wonder if there isn't a better way to do this, which would involve fixing the Wizard code instead. I'm not deep enough into Lift to offer to do that, but I will try if/when I get there.

Take care,
Chris.

Diego Medina

unread,
May 18, 2012, 5:12:50 PM5/18/12
to lif...@googlegroups.com

Yes, David asked me to look into it and I'm planning on it.

Diego
Sent from my android cell

Alexandre Richonnier

unread,
Dec 10, 2012, 4:57:26 PM12/10/12
to lif...@googlegroups.com
Hello !

Your code, Diego, scala-lift-custom-wizard with statefulsnippet is very helpful!
Thank you!
It's a good alternative to wizard.
I will probably use this pattern in my project.
But I can find a way to fix the issue that the first

screen does not support the back button, but the 2,3 and 4th page do
I tried registerThisSnippet(), I considered using SessionVar[Map[String, StatefulSnippet]] but it is not very elegant and secured.

All that can say, is that after press browser back button to go to "first" screen, S._statefulSnip is empty.

have you any idea how to fix it?

Cheers,

Alexandre

Diego Medina

unread,
Dec 11, 2012, 11:11:08 PM12/11/12
to Lift
I'll try to look at this later this week.

Diego
> --

Alexandre Richonnier

unread,
Dec 12, 2012, 3:04:04 AM12/12/12
to lif...@googlegroups.com
Thank you.

Alexandre

Reply all
Reply to author
Forward
0 new messages