<<< Part 1: Displaying the Form Post

Part 2: Managing the Form Post

Part one of this post dealt with setting up and displaying our form. This part deals with actually handling the form post itself. If you haven't already, read and create all the resources from part one.

POSTs and GETs are very similar. If you don't know the difference take a look here. The key thing to remember is that all of the posted or getted (yes, i know not a word) parameters are available to you in Obyx in the space 'sysparm'. So to reference a posted parameter called 'myParm' you would use the following input:

<input space="field" value="myParm" />
Returns the value of the parameter myParm

In order to update the database we need to run a query. We could use and iteration with an empty body but there is a slightly cleaner way: use an instruction with the operation 'query'. Heres an example:

<instruction operation="query">
    <input>update mytable set tstamp=now()</input>
</instruction>
sets all the fields called tstamp in the table mytable to the value now() (the current time)

Creating the Post Handler

With that little bit of theory out of the way we need to create the form handler itself. Create a new file called formhandler.obyx.For now, we'll simply put in an instruction that updates the table data to a static value:

formhandler.obyx:

<instruction xmlns="http://www.obyx.org">
    <input>
      
        <instruction operation="query">
            <input>update simpleFormDB set title='Jaws', director='Steven Spielberg' where id=1</input>
        </instruction>   
        
    </input>
</instruction>

You can run this code direcly in the browser by navigating to formhandler.obyx. If you then go back to showform.obyx you will see the form values have changed.

Making it work with Parameters

GET and POST parameters are treated the same in Obyx so we can test our form handler with URL parameters first before attaching it to our form. We can do this simply by constructing our URL with the parameters inline. e.g. http://localhost/formhandler.obyx?title=Alien&director=Ridley+Scott

We need to change our Obyx code so that instead of the static values 'Jaws' and 'Steven Spielberg' we use the values provided by the parameters 'title' and 'director'. We do this by simply contructing the query in stages, appending each input as we go:

<instruction operaiton="append">
   <input>update simpleFormDB set title='</input>
   <input space="sysparm" value="title" encoder="sql"/>
   <input>', director=</input>
   <input space="sysparm" value="director" encoder="sql"/>
   <input>' where id=1</input>
</instruction>
Constructs the query string: update simpleFormDB set title='SYSPARM:title', director=''SYSPARM:director'  where id=1

This instruction needs some explanation: Its operation is 'append'. This means that its output will be the result of all of its inputs concatenated together. So we split the SQL query into individual components and put each component into an input element.

Two of the inputs reference the space 'sysparm'. This space is where the URL parameters can be found, and the value is the name of the parameter ('title' and 'director'). Note that each of these also has an 'encoder' attribute and its value is 'sql'. This is Very Important!. You must always ensure any user content inserted into sql queries is encoded using the encoder to ensure against injection attack.

The complete code up to now is below, try running it in your browser:

formhander.obyx: (complete to this point)
<instruction xmlns="http://www.obyx.org">
    <input>
      
        <instruction operation="query">
            <input>
                   <!-- construct the query -->
                   <instruction operation="append">
                       <input>update simpleFormDB set title='</input>
                       <input space="sysparm" value="title" encoder="sql"/>
                       <input>', director='</input>
                       <input space="sysparm" value="director" encoder="sql"/>
                       <input>' where id=1</input>
                   </instruction>
    
            </input>
        </instruction>   
        
    </input>
</instruction>

Aggh Error!

When you run this code you will get an error that reads something along the lines of:

Error. input:Parameter title does not exist.

This error is being reported because you have not specified the 'title' or 'director' parameters in your calling URL. Try access the page again but this time supply some parameters.
e.g. http://localhost/formhandler.obyx?title=Spiderman&director=Sam+Raimis

You should find you get a blank screen rather than an error, but if you look in the database or flip back to showform.obyx you should see the values have changed according to the parameteres you entered

To avoid this error message we should check that the parameters have been provided. The comparison flow-function allows us to check if the parameters exist and branch the code accordingly:

<comparison operation="existent">
    <comparate space="sysparm" value="title" />
    <comparate space="sysparm" value="director" />
    <ontrue>All parameters correct</ontrue>
    <onfalse>Some parameters were missing</onfalse>
</comparison>

The comparison operation is an if-then-else construct. It compares the supplied input(s) using the specified operation (in this case 'existent') and executes the ontrue or onfalse code blocks as necessary. We therefore need to put all of our code so far into the ontrue component of this, as follows:

formhandler.obyx:

<instruction xmlns="http://www.obyx.org">
    <input>
    
    <!-- check all parameters exist -->
    <comparison operation="existent">
        <comparate space="sysparm" value="title" />
        <comparate space="sysparm" value="director" />
        <ontrue>
            <!-- all parameters present so execute update -->
            <instruction operation="query">
                <input>
                    <!-- construct the query -->
                    <instruction operation="append">
                        <input>update simpleFormDB set title='</input>
                        <input space="sysparm" value="title" encoder="sql"/>
                        <input>', director='</input>
                        <input space="sysparm" value="director" encoder="sql"/>
                        <input>' where id=1</input>
                    </instruction>
                    
                </input>
            </instruction>         
        </ontrue>
        <onfalse>
            Some parameters were missing!
        </onfalse>
    </comparison>

    </input>
</instruction>

If you run this now without parameters you will get our slightly nicer error message. Running with the parameters will run the update (and return a blank screen).

Putting it all Together

We now have a working form and a working form handler, but the two dont yet talk to each other First of all we'll change our form so that when you save it posts to the form handler. To do this, we need to change the 'action' attribute of the form in the view to reference the form handler. Change the form tag as follows:

<form  method="post" enctype="multipart/form-data" action="formhandler.obyx"> 

Thats it! If you test the form now you should be able to change the values of the database by sumitting the form.

We're still getting a blank page after the post. So we need to tell our form handler to redirect the user. You may want to redirect to a thankyou page but in this case we'll just redirect back to the form. To do this we need to set a 302/Location header. We need to add this code into the ontrue code block, justafter the SQL update: (Theres more about redirection in the HTTP Redirection post).

<instruction note="Set the http location">
	<output space="http" value="Location" />
	<input value="showform.obyx" />
</instruction>
<instruction note="Set the http code to a temporary redirect">
	<output space="http" value="Code" />
	<input value="302" />
</instruction>

We're done! Thats the last piece of the puzzle, for this post at least. If you now change the values and submit the form you should see the database updates and the form reloads with the relevant data. Note: You can find the complete source code to this post at the end.

Future posts

This was a pretty basic form, future posts will look into further complexities such as:

  • Merging the form display and handler into a single file
  • Displaying different records via URL parameters
  • More interesting form elments such as select and file uploads.
- James
12 October 2009

Complete Source Code

form_view.html:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
    <head><title>Edit Form Example</title></head>
    <body>
        <h1>My Example Form</h1>
        <form  method="post" enctype="multipart/form-data" action="formhandler.obyx"> 
            <fieldset>
                <input type="hidden" name="id" value="0"/>
                <ul id="segmentData">
                   <li>
                      <label>Title:  <input name="title" value="" /></label>
                   </li>
                    <li>
                        <label>Director:  <input name="director" value="" /></label>
                    </li>
                    <li>
                        <input type="submit" value="Save" />
                    </li>
                </ul>
            </fieldset>
        </form>
    </body>
</html>
showform.obyx:

<instruction xmlns="http://www.obyx.org">
    <input>
        <!-- set the html naespace prefix for xpaths -->
        <instruction>
            <output space="namespace" value="h" />
            <input value="http://www.w3.org/1999/xhtml" />
        </instruction>
        
        <!-- Load the view template into store called mainView -->
        <instruction>
            <output space="store" value="mainView" />
            <input space="file" value="form_view.html" />
        </instruction>    

        <!-- Populate the form -->
        <iteration operation="sql">
        <control>select id,title, director from simpleFormDB where id=1</control>
        <body>    
            <instruction>
                <output space="store" value="mainView#//h:input[@name='title']/@value" />
                 <input space="field" value="title" />
            </instruction>
            <instruction>
                <output space="store" value="mainView#//h:input[@name='director']/@value" />
                <input space="field" value="director" />
            </instruction>
            <instruction>
                <output space="store" value="mainView#//h:input[@name='id']/@value" />
                <input space="field" value="id" />
            </instruction>
        </body>
        </iteration>

        <!-- output the view to screen -->
        <instruction>
            <input space="store" value="mainView" release="true" />
        </instruction> 

    </input>
</instruction>
formhandler.obyx:

<instruction xmlns="http://www.obyx.org">
    <input>
    
    <!-- check all parameters exist -->
    <comparison operation="existent">
        <comparate space="sysparm" value="title" />
        <comparate space="sysparm" value="director" />
        <ontrue>
            <!-- all parameters present so execute update -->
            <instruction operation="query">
                <input>
                    <!-- construct the query -->
                    <instruction operation="append">
                        <input>update simpleFormDB set title='</input>
                        <input space="sysparm" value="title" encoder="sql"/>
                        <input>', director='</input>
                        <input space="sysparm" value="director" encoder="sql"/>
                        <input>' where id=1</input>
                    </instruction>
                    
                    <!-- redirect the user to the form page -->
                    <instruction note="Set the http location">
                        <output space="http" value="Location" />
                        <input value="showform.obyx" />
                    </instruction>
                    <instruction note="Set the http code to a temporary redirect">
                        <output space="http" value="Code" />
                        <input value="302" />
                    </instruction>
                    
                </input>
            </instruction>         
        </ontrue>
        <onfalse>
            Some parameters were missing!
        </onfalse>
    </comparison>

    </input>
</instruction>



Last Modified: Thu, 15 Jan 2015