bvstone

Converting a Standard HTTP Form POST to jQuery .post() Method

Posted:

Converting a Standard HTTP Form POST to jQuery .post() Method

If you have been creating web applications over the years like I have, it seems like every day there are new features available to us, even if we're using RPG for our web application language.

One of my favorite tool sets, as you can tell by most of my articles, is jQuery.  

This example will show how you can use jQuery to update the method of POSTting (or even GETing) data.  We can take the "old" method of a simple form submission and very easily update it to use the jQuery .post() method.

For this example I chose to update a sample program that comes with the eRPG SDK.

If we go to the samples page for the eRPG SDK we see a sample program named Input2.  All this program does is read in data and then report it back to the screen using all of the different methods available to read and convert the input data.  The final program can be seen here.

First we display the HTML form:

<html>
<body>
<form action="/e-rpg/input2" method="post">
  Data: <input type="text" name="data">
  <input type="submit">
</form>
</body>
</html>

It's obvious from this HTML that when the use clicks the Submit button it will run program INPUT2.  This is a very simple program that reads in the data and writes that data back out using each of the available options for the #setDataCase() function within the eRPG SDK.  No, it's not free format.  It was written long before that was available (lol):

     H DFTACTGRP(*NO) BNDDIR('ERPGSDK')                                                             
      ****************************************************************                              
      * Prototypes                                                   *                              
      ****************************************************************                              
      /COPY QCOPYSRC,P.ERPGSDK                                                                      
      ****************************************************************                              
     D Data            S           1024                                                             
      ****************************************************************                              
     C                   callp     #startup                                                         
      *                                                                                             
     C                   callp     #loadTemplate('input2.erpg')                                     
     C                   eval      Data = #getData('data')                                          
     C                   callp     #replaceData('/%asis1%/':Data)                                   
      *                                                                                             
     C                   callp     #setDataCase(UPPER)                                              
     C                   eval      Data = #getData('data')                                          
     C                   callp     #replaceData('/%upper1%/':Data)                                  
      *                                                                                             
     C                   callp     #setDataCase(LOWER)                                              
     C                   eval      Data = #getData('data')                                          
     C                   callp     #replaceData('/%lower1%/':Data)                                  
      *                                                                                             
     C                   callp     #setDataCase(AS_IS)                                              
     C                   eval      Data = #getData('data')                                          
     C                   callp     #replaceData('/%asis2%/':Data)                                   
      *                                                                                             
     C                   eval      Data = #getData('data':1:UPPER)                                  
     C                   callp     #replaceData('/%upper2%/':Data)                                  
      *                                                                                             
     C                   eval      Data = #getData('data':1:LOWER)                                  
     C                   callp     #replaceData('/%lower2%/':Data)                                  
      *                                                                                             
     C                   eval      Data = #getData('data')                                          
     C                   callp     #replaceData('/%asis3%/':Data)                                   
      *                                                                                             
     C                   callp     #writeSection                                                    
     C                   callp     #cleanup                                                         
      *                                                                                             
     C                   eval      *INLR = *on     

The template used with this program is also very simple:

Content-type: text/html
Pragma: no-cache
Expires: Saturday, February 15, 1997 10:10:10 GMT

<html>
<body>
Data read in using #getData(variable).<br>
/%asis1%/
<br>
<br>
Data read in after using #setDataCase(UPPER).<br>
/%upper1%/
<br>
<br>
Data read in after using #setDataCase(LOWER).<br>
/%lower1%/
<br>
<br>
Data read in after using #setDataCase(AS_IS).<br>
/%asis2%/
<br>
<br>
Data read in after using #getData(variable:UPPER)<br>
/%upper2%/
<br>
<br>
Data read in after using #getData(variable:LOWER)<br>
/%lower2%/
<br>
<br>
Data read in using #getData(variable).<br>
/%asis3%/
</body>
</html>

This application works great and does what we want, but today users want things to be more interactive.  Moving from one screen to another just doesn't fit the flow of most modern applications today.

In order to update this application we will use jQuery and it's .post() method instead of doing a straight HTTP POST from the web form.  And the great thing is, we don't need to change our template or CGI program at all.  All we need to do is update the main page.  In this case we just copied the input2.html file to a new page named input3.html  The source of which follows:

<html>
  <body>
    <form action="/e-rpg/input2" id="showMeDataForm" method="post">
      Data: <input type="text" name="data">
     <button type="button" id="showMeDataButton">Submit</button>
    </form>
    <div id="showMeDataDiv"></div>
    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>
    <script src="//cdnjs.cloudflare.com/ajax/libs/jquery.blockUI/2.66.0-2013.10.09/jquery.blockUI.min.js"></script>
    <script>
      $(document).ready(function(){
      
        $('#showMeDataButton').click(function(e) {
          	showMessage('Retrieving Data...');
            var formData = $('#showMeDataForm').serialize();
            var postURL = $('#showMeDataForm').attr('action');
            
            $.post(postURL, formData)
              .done(function(data) {
                $('#showMeDataDiv').html(data);
              })
              .fail(function(xhr, status, error) {
                $('#showMeDataDiv').html('There was an error!  See the console.');
                console.log('status' + status);
                console.log('error:' + error);
              })
              .always(function(data) {
                $.unblockUI();
              })
        });  
      
      });
      
      function showMessage(text) {
        $.blockUI({
          message:text,
          css: { 
                 border: 'none', 
                 padding: '15px', 
                 backgroundColor: '#000', 
                 '-webkit-border-radius': '10px', 
                 '-moz-border-radius': '10px', 
                 opacity: .5, 
                 color: '#fff' 
                }
        	});
      }
    </script>
  </body>
</html>

For this example I did choose to put all the JavaScript in the main page itself.  In real world applications I would move the JavaScript into it's own external file.  But, this way we have everything in one place to discuss how it works.

The first change we see is from the form itself.  

OLD:
    <form action="/e-rpg/input2" method="post">
      Data: <input type="text" name="data">
      <input type="submit">
    </form>

NEW:
    <form action="/e-rpg/input2" id="showMeDataForm" method="post">
      Data: <input type="text" name="data">
     <button type="button" id="showMeDataButton">Submit</button>
    </form>
    <div id="showMeDataDiv"></div>

Notice first we have given an ID to our form with the value of showMeDataForm.  

Next, we have replaced the submit button with an actual HTML button, also with an ID of showMeDataButton.  And finally we've added an empty DIV container named showMeDataDiv.  This is where the results of our POST will be placed.  This is instead of the old method of going to a completely different page.  (Please note, IDs when used with jQuery MUST BE UNIQUE on each element or they will NOT work.)

The next obvious update is the addition of a few <script> containers.

    <script src="//ajax.googleapis.com/ajax/libs/jquery/2.2.3/jquery.min.js"></script>

This first script container loads jQuery version 2.2.3 from Google's CDN, a Hosted Library of many popular JavaScript Libraries (and many thanks to Google for hosting these.. let's just hope they don't one day shut it down).  Using a CDN will allow your pages to load faster and save bandwidth for your network.  This is because the JavaScript library(ies) are loaded from an external source.

    <script type="text/javascript" src="//cdnjs.cloudflare.com/ajax/libs/jquery.blockUI/2.66.0-2013.10.09/jquery.blockUI.min.js"></script>

This next script container loads a library known as BlockUI.  This is one library that isn't hosted by Google, but with most libraries like this you can normally find them out there somewhere.  What this library allows us to do is to show the user a status message when they click the submit button.   It also "blocks" the screen so that the user cannot click any buttons again, hence the name BlockUI.

    <script>
      $(document).ready(function(){
      
        $('#showMeDataButton').click(function(e) {
          	showMessage('Retrieving Data...');
            var formData = $('#showMeDataForm').serialize();
            var postURL = $('#showMeDataForm').attr('action');
            
            $.post(postURL, formData)
              .done(function(data) {
                $('#showMeDataDiv').html(data);
              })
              .fail(function(xhr, status, error) {
                $('#showMeDataDiv').html('There was an error!  See the console.');
                console.log('status' + status);
                console.log('error:' + error);
              })
              .always(function(data) {
                $.unblockUI();
              })
        });  
      
      });
      
      function showMessage(text) {
        $.blockUI({
          message:text,
          css: { 
                 border: 'none', 
                 padding: '15px', 
                 backgroundColor: '#000', 
                 '-webkit-border-radius': '10px', 
                 '-moz-border-radius': '10px', 
                 opacity: .5, 
                 color: '#fff' 
                }
        	});
      }
    </script>

Finally we have the main JavaScript code that does the interactive POST using jQuery's .post() method.

When using jQuery, normally we place most functions inside jQuery's document.ready() method block so that nothing will execute until the entire page is loaded.

Next we see we are assigning a function when the user clicks the button with the Id showMeDataButton.  We first serialize the form data using the serialize() method.  Put quite simply, this method "serializes" the form data, placing it in a name=value pair string just as we would expect data when doing a GET or POST (ie, field1=data1&field2=data2....)

Before making our post we will use the BlockUI function to display a message on the screen as well as block the UI on the page so the user can't click the button repeatedly (ya, this never happens... haha).  I have encapsulated the BlockUI function in the showMessage() function to make things more readable.  Normally in larger systems we will have many calls to BlockUI and this just makes things easier to read and use.

Next we use the attr() function to retrieve the "action" attribute from our form so that we know where to do our .post().

Finally, we call the .post() method.  This uses AJAX in the background to make the POST to our CGI program.  This is really the same as letting our form do the POST, except that all of the action is encapsulated inside the .post() function and we can do what we want with the returned results.

Another neat feature is that the .post() method allows the use of multiple callbacks for specific actions.  In our case we are using .done(), .fail(), and .always() callbacks which do exactly what we would expect.  .done() will be called when the the .post() completes normally .fail() is called if there is an error (normally resulting from a none 200 type status code from the .post()), and .always() will be called, well, always.    

When the .post() completes normally we use the .html() method to update the contents of our (what was empty) DIV container with the ID showMeDataDiv.

If we encounter a server error, the .fail() method is called and we update our showMeDataDiv with an error message and write the error details to the console using console.log() (which happens to be one of my favorite debugging tools.)

Finally, the .always() method will be called no matter what happens.  In this method we will "un-block" the display using the BlockUI method of .unblockUI().  This will return the page to it's previous state where the user can again interact with it.

So, as you can see, updating your CGI applications to be more interactive and user friendly doesn't have to be too difficult.  In fact, in most cases the CGI programs themselves won't need to change much, if at all.  Feel free to try out the application yourself by following this link.


Last edited 05/08/2017 at 10:07:00




Reply




© Copyright 1983-2024 BVSTools
GreenBoard(v3) Powered by the eRPG SDK, MAILTOOL Plus!, GreenTools for Google Apps, jQuery, jQuery UI, BlockUI, CKEditor and running on the IBM i (AKA AS/400, iSeries, System i).