in reply to Why is my CGI.pm script trying to assign data before pressing submit.

I'll try to answer your question, but first a few curmudgeonly comments:

  1. From your node title, it sounds like you may be making a classic new CGI programmer's thought error. You are not coding a continuous process. Each request your CGI script gets runs as a separate, unique invokation of your script. The last person I taught CGI scripting had to be reminded of this fact about 1000 times before she got it.
  2. Be very careful taking filenames as input from a cgi. There are many nodes about this. Check out ovid's cgi tutorial for a treatment of this. Also read perlsec.
  3. Are you familiar with the state machine model of CGI programming? (Try a Super Search for "state machine" more info.) The idea is that your CGI script needs a way to remember what part of the interactive process it is presenting.

    Your script would probably have three states, let's call them "edit", "preview", and "commit".

    "Well and good, but how do organize this?" you might be thinking. The most common method is to use a parameter with a name like "state" or "action". You can then define the behavior for each state by using a big fat case statement. There is no native case statement in perl, but a chain of elsif statements works very nicely.

    # Set state to edit if not defined. param(state)||param(name=>'state', value=>'edit'); if (param('state') eq 'edit') { # display the form print start_form('POST',self_url()); # blah blah blah print submit('state','preview'), end_form(); } elsif (param('state' eq 'preview') { # display the results, prettily. print start_form('POST',self_url()), # A bunch of hidden fields to pass our data along hidden(parameter-n, value), # This button commits the data to a file. submit('state','commit'), # This button returns to the edit form, to make changes. submit('state','edit'), end_form(); } elsif ( param('state') eq 'commit') { # Save the file # Print some nice messages. } else { # General purpose error. You should never wind up here # Trap it just in case. }

    I personally, prefer to use here docs for embedding HTML in my perl. I find CGI.pm's HTML generation cumbersome. But some people really like it, TIMTOWTDI. I always use CGI.pm for parameter management though.

    # A sample here doc print <<"END_OF_HTML"; Blah laalbalalsdfasdf asdf blaha END_OF_HTML


    TGI says moo

Replies are listed 'Best First'.
Re: Re: Why is my CGI.pm script trying to assign data before pressing submit.
by andye (Curate) on Dec 07, 2001 at 14:37 UTC
    I find CGI.pm's HTML generation cumbersome.

    That's a relief, I thought it was just me.
    andy.

Re: Re: Why is my CGI.pm script trying to assign data before pressing submit.
by Amoe (Friar) on Dec 07, 2001 at 22:08 UTC
    In cases like this, it can be cleaner to use a hash lookup table:
    my %lookup = (edit => sub { let_the_user_edit_it() }, preview => sub { preview_it() }, commit => sub { commit_to_get_fit() }); $lookup{param('state')}->();


    --
    my one true love

      I thought I'd stick with the basic technique of an if else chain, to keep things simple on the perl end of things. But, if you don't mind working with references (which are something every perl programmer should learn to use), a hash of subroutine refs is a most excellent technique.

      my %lookup = (edit => \&let_the_user_edit_it, preview => \&preview_it, commit => \&commit_to_get_fit, ERROR => \&non_existant_state ); if exists $lookup{param('state')} { $lookup{param('state')}->(); } else { $lookup{ERROR)}->(); }

      I made a couple of changes to your code. Storing the subroutine addresses directly, saves one round of subroutine dispatch, a negligable performance savings, but it removes 1 level of indirection and saves on typing--to my mind, it's tidier. I also check for the existance of the hash key before trying to execute its code reference. This lets you give a better feedback in your error page than a plain 500 error usually does.


      TGI says moo