yardpenalty yardpenalty - 3 months ago 28
JSON Question

POST using $.ajax() instead of $.getJSON() when JSONP is required RPGLE IBM i PACE

Can someone please explain and demonstrate the correct way to implement jQuery ajax without having to use

$.getJSON()
for everything (ie:
GET, PUT, POST, DELETE
) in an IBM i environment? I dont want to pass my parameters the traditiontal way eg:
$('[name="EMAIL"]').val()
rather I want to pass JSON object string eg:
{"form" : [{ "email": "yardpenalty@yahoo.com"}]}
.

We are able to perform PostToGet callbacks using the
$.getJSON()
method as such but I can't use
$.ajax
unless I post form object correct?

PHP/JS:

// load all parameters
data = 'INSTANCE=<?echo trim($PATH_INSTANCE)?>' +
'&FUNCTION=<?echo urlencode(trim($FUNCTIONCODE))?>' +
'&USER=' + $('[name="USER"]').val() +
'&CONTACT=' + w$('[name="CONTACT"]').val() +
'&EMAIL=' + $("input[name='EMAIL']").val() +
'&MSG=' + $('[name="MSG"]').val() +
'&TYPE=' + $('[name="TYPE"]').val();

// Call the RPG REST JSONP program
$.getJSON( "http://www.domain.com:8082/rest/RPGLEPGM?callback=?",data )
.done(function( json ) { ... }

//Domain is actually
http://www.domain.com:8081


RPGLE PGM:

Begsr $Incoming;

cgiPostToGet(); // Convert POST to GET

callback = cgiParseGet('callback'); // callback

p#Function = cgiParseGet('FUNCTION');
Endsr;


But I want to be able to use the other AJAX methods doing various actions such as simply updating records
.post()/.ajax()
on the fly or simple
.get()
ajax calls without creating a callback. I don't want to have to use getJSON every time I use ajax not to mention its bad practice to POST on a GET, but from what I understand the
.getJSON()
provides JSONP functionality while the others do not by default.

EDIT: We do have our ajax RPGLE PGMS on a different port than the actual website so JSONP is necessary and the client knows its JSONP because we pass the
callback
function back.

Answer

Since our ajax RPGLE PGM CALLS are on a different port than the PHP requests (think different domains on a host server) this qualifies as cross-domain requests; therefore, we must pass the &callback=? function/wrapper back to the client using JSONP (or Cors if security is an issue). I found a really good piece on JSONP here on SO and this is exactly what this ajax call is using.

RPGLE the jQuery ajax requests are made possible by using some sort of CGI API accessible on your OS/400 - IBM i Web environment. When calling (CALLB or CALLP) an RPGLE PGM using ajax we are actually making a procedural call, but when using global temps we are actually making a SQL Procedural CALL which is way more expensive in terms of resources which is why Web Services are becoming more popular.

It is more practical to not only pass javascript objects from the form data on request but to return JSON objects with Ajax requests than storing global temp data in the db2 environment and processing it into a PHP array on the response.

By processing the JSON string on the client instead of using both server memory and drive space and disk read/writes necessary for PHP arrays and global temp files we are really able to take advantage of more modern web design practices.

Here is a working example of using $.ajax/PHP/RPGLE correctly without using $.getJSON():

<script>

$(document).ready(function(){
     GetEmail("#email", '<?php echo trim($USER)?>', '<?php echo $PATH_INSTANCE?>');
     FormValidation();
});

    function FormValidation(){
        //Variables created without the keyword var, are always global, even if they are created inside a function.
        var form = $('#<?echo $PAGEID?>');
        var FormError = $('.alert-danger',form);
        var success = $('.alert-success',form);

         form.validate({

        focusInvalid: false, // do not focus the last invalid input
        onkeyup: false, 
        ignore: ".ignore", //required for hidden input validation ie: hiddenRecaptcha
        rules:{
            "TYPE": {
                required: true,     
            },
            "MSG": {
                required: true,
                rangelength:[40,1000]
            },
            "CONTACT": {
                 required: {
                     depends: "#newuser:checked"
                 }
            },
            "EMAIL": {
                 required: true,
                 email: {
                    depends: function() {
                        if(!$("#newuser:checked"))
                            return true;
                        else
                            return false;
                    }
                 },
                 HTH_TelephoneEmail: {
                        depends: function() {
                            if($("#newuser:checked"))
                                return true;
                            else
                                return false;
                        }
                     }
            },          
            hiddenRecaptcha: {
                required: function () {
                    if (grecaptcha.getResponse() == '') {
                        return true;
                    } else {
                        return false;
                    }
                }
            }
        },
        messages: { // custom messages for form validation input
               "TYPE": {
                    required: 'Please select an option as it pertains to your inquiry'
               },
               "MSG": {
                    required: 'Please provide some content as it pertains to your inquiry'       
               },
               "CONTACT": {
                required: "Please enter a contact person or company"
               },
              hiddenRecaptcha: {
                required: function() {
                    $(".g-recaptcha:first").tooltip("enable").tooltip("show");
                }
              }
        },
        showErrors: function(errorMap, errorList) {
            // Clean up any tooltips for valid elements
            $.each(this.validElements(), function (index, element) {
                element = $(element);
                NoError_ToolTip(element);
            });
            // Create new tooltips for invalid elements
            $.each(errorList, function (index, error) {
                element = $(error.element);
                message = error.message;
                Error_ToolTip(element,message);
            });
        },                  
        invalidHandler: function (event, validator) { //display error alert on form submit     
            success.hide();
            $(document).scrollTop( $(".form-body").offset().top ); 
        },
         submitHandler: function () {
             Submit_Complete(); 
             }
    });

     function Submit_Complete(){

           var obj = form.serializeObject();
            console.log(obj);

          $(".g-recaptcha:first").tooltip("disable").tooltip("hide");
            $('.shell').html('<div class="loading"><span class="caption">Sending...</span><img src="/images/loading.gif" alt="loading"></div>');

            $.ajax({
           type: "POST",
           url:  "http://www.domain.com:8082/rest/RPGPGM2?callback=?",
           data:  obj,
           //contentType: "application/json; charset=utf-8",
           dataType: "jsonp"}).
           done(function(data){
               $(".shell").html('<label class="msg xs-small">' + data["MESSAGE"] + '</label><br><br><br><br><br><br><br><br><br>'+
                '<div class="caption right">'+
                '<a href="index.php" id="defaultActionButton" class="btn green">Home&nbsp;<i class="fa fa-home"></i></a>'+
                '</div>');
           }).
           fail(function(){
               $(".shell").html("<label class='msg xs-small'>We're Sorry!<br><br><br><br><span class='text-danger'>Unfortunately this inquiry cannot be processed at this time." +
               "<br>Please try again at a later time or give us a call at:</span><br><br>+1.800.406.1291</label><br><br><br><br><br><br><br><br><br>"+
                        '<div class="caption right">'+
                        '<a href="index.php" id="defaultActionButton" class="btn green">Home&nbsp;<i class="fa fa-home"></i></a>'+
                        '</div>');
           });
    }
}

/** * Serializes form data/objects. This actually creates a javascript object which our CGIAPI is capable of handling! * */

 $.fn.serializeObject = function() {
    var o = {};
    var a = this.serializeArray();
    var $value = '';
    $.each(a, function() {
        if (o[this.name]) {
            if (!o[this.name].push) {
                o[this.name] = [o[this.name]];
            }
            o[this.name].push(this.value || '');
        } else {
            o[this.name] = this.value || '';
        }
    });
    return o;
};

</script>

We can make RESTful calls by using some type of CGI API such as QtmhWrStout or by creating Web Services. This solution is of the former.

Here is a list of the basic CGI APIs:

enter image description here

RPGLE PGM:

   //  $Incoming: Test and load the incoming parameters

   Begsr $Incoming;

     cgiPostToGet(); // Convert POST to GET

     callback = cgiParseGet('callback'); // never delete - unique key for the request

     p#UserID = cgiParseGet('USER');
    if (%scan(#lf:p#UserID) <> 0);
         p#UserID = *blanks;
    endif;

    p#Instance = cgiParseGet('INSTANCE');
    if (%scan(#lf:p#Instance) <> 0);
         p#Instance = *blanks;
    endif;

    p#Function = cgiParseGet('FUNCTION');

    p#Contact = cgiParseGet('CONTACT');
    if (%scan(#lf:p#Contact) <> 0);
         p#Contact = *blanks;
    endif;

    p#Email = cgiParseGet('EMAIL');
    p#Msg = cgiParseGet('MSG');
    p#Related = cgiParseGet('TYPE');

     exsr $InzSr;

    Endsr;

       Begsr $Outgoing;

          // Tell Consumer that a JSON string will be sent
          ajx_data = 'Content-type: text/javascript' + CRLF + CRLF; // DO NOT CHANGE THIS LINE!!!
          QtmhWrStout(ajx_data: %len(%trimr(ajx_data)): ajx_err);// DO NOT CHANGE THIS LINE!!!
          ajx_data = %trim(callback) + '(' + %char(LBrace);       // DO NOT CHANGE THIS LINE!!!
          QtmhWrStout(ajx_data: %len(%trimr(ajx_data)): ajx_err);// DO NOT CHANGE THIS LINE!!!

           ajx_data = '"MESSAGE":"' + %trim(p#message) + '"';
           QtmhWrStout(ajx_data: %len(%trimr(ajx_data)): ajx_err);

          // load the final right brace to complete the JSON string
          ajx_data = %char(RBrace) + ');';                          // DO NOT CHANGE THIS LINE!!!
          QtmhWrStout(ajx_data: %len(%trimr(ajx_data)): ajx_err);  // DO NOT CHANGE THIS LINE!!!

       Endsr;

****NOTE****

If we can't serialize our form directly we must build a javascript object like this:

       var obj = {USER : localProfile,  
        INSTANCE : "HTHACKNEY",  
        PAGE : $('select[name="PAGE"]').val(), 
        TITLE : $("input[name='TITLE']").val(), 
        HTML : html,
        STARTDATE : $("input[name='STARTDATE']").val(), 
        ENDDATE : $("input[name='ENDDATE']").val(),
        ARCHIVE : $("input[name='ARCHIVE']").val(), 
        ACTIVE : $("input[name='ACTIVE']").val(), 
        URGENT : $("input[name='URGENT']").val(), 
        AUTHLST :  authStr};

  $.ajax({
            type: "POST",
           url:   "http://webservices.hthackney.com/web054S?callback=?",
           data:  data,
           dataType:'jsonp'
       }).done({ //do something on success });