Showing posts with label Ajax. Show all posts
Showing posts with label Ajax. Show all posts

Friday, January 17, 2014

Experimenting with Node.js

Node.js seems particularly suited for small real-time web pages where users can see event-driven data be updated on the webpage without a page refresh.  I spent a couple hours this weekend learning about node.js so I made a simple long polling web server based on one of the examples from this article.

To get my Ubuntu VM ready to do this, I did the following:
-downloaded the node-v0.10.24-linux-x64.tar.gz and untarred the package.  I had all the prereqs from the README.md file, except python
-installed python 2.7.2.  Since I hadn't used python scripting before, decided to dabble a bit in that by writing a few statements in a python script to get used to python syntax

The Simple Long Polling Web Server Example:
The node.js web server is polling every 10000 milliseconds, and if the current time in milliseconds modulus 3 is zero, then it returns the time to the caller.  A simple html webpage is making an ajax call to the node.js web server, and will append the time if conditions are satisfied.  Here's the output of it:






















Files:

  1. server_longpoll.js:
    var sys = require('sys'),
       http = require('http');
    
    http.createServer(function(request, response) {
      getTime(request, response);
    }).listen(8000);
    
    function getTime(request, response)
    {
      var now = new Date();
      var timeInMilliseconds = now.getTime();
    
      // event that is listening is: if time is modular by 3
      if ((timeInMilliseconds % 3) == 0)
      {
        // return the contents
        response.writeHead(200, {
          'Content-Type'   : 'text/plain',
          'Access-Control-Allow-Origin' : '*'
        });
    
        // return response
        response.write(timeInMilliseconds.toString());
        response.end();
    
        // return
        return false;
      }
    
      setTimeout(function() {getTime(request, response) }, 10000);
    
    };
    
  2. cherryshoe_longpoll.html:
    <head>
    <meta charset="UTF-8">
    <title>Sample ajax call to node server with long polling</title>
    </head>
    
    <body>
    Polling every 10000 milliseconds... </br>
    Current time in milliseconds where modulus 3 is zero: <div id="updateId"></div>
    
    
    <script src="jquery-1.9.1.js"></script>
    <script src="cherryshoe_longpoll.js"></script>
    </body>
    </html>
    
  3. cherryshoe_longpoll.js:
    $(document).ready(function() {
            function callNodeJs() {
                    $.ajax({
                            // setup the server address
                            url : 'http://judyhost:8000',
                            success : function(response, code, xhr) {
                                // on success
                                $('#updateId').append(response + "</br>");
                                    callNodeJs();
                            },
                            error : function() {
                              // on error
                              alert("error");
                            }
                    });
            };
    
            callNodeJs();
    });
    
This example is obviously very simple, but can easily be modified to watch for ANY event to happen and solved in the same fashion.

Thursday, December 26, 2013

The power of javascript closures

Recently, I've fixed several issues in my web application where "sometimes things work, and sometimes they don't".  When I hear statements like that, often it points to a UI javascript timing issue.
  1. Checking if a ajax call returns any data OUTSIDE of the ajax success block.  For example with jQuery:
  2. doSomething: function()
    {
        var isData = false;
        $.ajax({
            url: url,
            type: "GET",
            success: function (jsonString) {
                // ... do some stuff
                isData = true;
            }
        });
        return isData;
    };
    
  3. Performing DOM manipulations with ajax return values OUTSIDE of the ajax success block.  For example:
  4. doSomething: function()
    {
        var jsonObj;
        $.ajax({
            url: url,
            type: "GET",
            success: function (jsonString) {
                jsonObj = jQuery.parseJSON(jsonString);
            }
        });
        
        // ... Manipulate DOM here with jsonObj data
    };
    

Since ajax calls are meant to be asynchronous, the call can return at any time.  You can't guarantee that the call will have returned when the red highlighted code is reached.

Both issues can be solved with Javascript closures.  Closures are powerful - developers often do not understand how (or when) to use them - so don't, or they are used incorrectly.  I've found this article to be the best, clearest, succinct article I have read on the subject.  In short - "A closure is a special kind of object that combines two things: a function, and the environment in which that function was created. The environment consists of any local variables that were in-scope at the time that the closure was created".

Closures work well with ajax calls, since you most likely want to display the return values of an ajax call on your web application.  The following are two examples where we explore DOM manipulation after an ajax call has completed in the success block.

EXAMPLE SOLUTIONS
We want to display the location "New York City" that belongs to the postal code "10014" when the "Find Postal" button is clicked.
  1. The simplest, most straight forward solution is DOM manipulation directly in the ajax success block of the performSearch function.  Take a look at the jsfiddle example http://jsfiddle.net/jhsu9/jAN6t/.
  2.     $.ajax({
            url: url,
            type: "GET",
            success: function (jsonString) {
                var jsonObj = jQuery.parseJSON(jsonString);
                var html = jsonObj.postalcodes[0].placeName;
    
                postalDiv.html(html);
            },
            error: function (xhr, textStatus) {
                alert("error");
            }
    
        }); // matches ajax end
    

  3. DOM manipulation happens with a closure, passed into the performSearch function as a callback function, and is invoked after the success block completes.  Take a look at the jsfiddle example http://jsfiddle.net/jAN6t/7/.
  4. performSearch = function (pCallback) {
        var url = "http://www.geonames.org/postalCodeLookupJSON?postalcode=10014&country=US";
    
        $.ajax({
            url: url,
            type: "GET",
            success: function (jsonString) {
                var jsonObj = jQuery.parseJSON(jsonString);
                var htmlData = jsonObj.postalcodes[0].placeName;
    
                // pCallback may either not exist or is undefined, checking for typeof callback == 'undefined' takes care of both
                if (!(typeof pCallback == 'undefined') && (typeof pCallback === "function")) {
                    // invoke the pCallback passed in, pass in any params if necessary
                    pCallback(htmlData);
                }
            },
            error: function (xhr, textStatus) {
                alert("error");
            }
    
        }); // matches ajax end
    
    };
    
    postalBtn.click(function () {
        // function to do the work
        function processFunction(pHtmlData)
        {
            alert("processFunction with data[" + pHtmlData + "]");
            postalDiv.html(pHtmlData);
        }
        // function factory, this will be passed into performSearch.
        // Essentially the callback will be a closure attached as a parameter to performSearch.
        // It's not until the callback is INVOKED will the inner function be called
        function processFunctionCallback()
        {
            alert("attached processFunctionCallback");
            return function(pHtmlData) {
                alert("invoke processFunctionCallback with data[" + pHtmlData + "]");
                processFunction(pHtmlData);
            };
        }
        
        performSearch(processFunctionCallback());
    });
    

    The performSearch function is passed an optional closure called processFunctionCallback() which has an inner function that is doing the actual work of updating the DOM; it's not until the closure/callback function is invoked that the inner function will be called.  Notice the data value "htmlData" has to be passed as a parameter to the closure / callback function in the ajax success block, in order for the inner function to know what value to display.

SUMMARY
Example Solution 2 is much more powerful.  The performSearch function can be invoked with various actions (i.e. Search button action, sort action, sort by column action, select all action, etc), so you want a generic way to do DOM manipulation after the ajax success completes.  By passing in a closure / callback function, each function can be unique as to what kind of DOM manipulation you want to happen after the performSearch completes.


Saturday, September 14, 2013

Spring 3.2 @ControllerAdvice to handle Controller Exceptions

My Java/Spring web application has controllers that either return ModelAndView to a jsp page or return json for ajax calls.  Exceptions can occur at any time, and I noticed that on ajax success the data returned was json, but on ajax error the data returned was regular text; all ajax calls should return the same kind of data, namely json.  There had to be a way to solve this problem generically!

Spring 3.2 to the rescue - it introduced a new annotation called @ControllerAdvice (http://docs.spring.io/spring/docs/3.2.x/spring-framework-reference/html/new-in-3.2.html#new-in-3.2-webmvc-controller-advice)  that defines methods that applies to all @RequestMapping rest url methods, and in particular to help with exceptions with @ExceptionHandler.  We can use this to have a generic exception handling solution to have all ajax calls return json, and all ModelAndView return html.

  • @ControllerAdvice allows you to define ONE controller class to handle ALL exceptions that could occur (no specific exceptions defined needed)
  • You can control the HTTP status code returned
  • You can control the json message returned by grabbing the exception message from the specific exception that occurred

Here's how you do it:
  1. Your controllers won't change, the code will still continue to throw any number of specific exceptions:
  2. @Controller
    public class ExceptionController {
        
        @RequestMapping(value = "/randomException", method = RequestMethod.GET)
        public String randomException(Authentication auth, HttpServletRequest request) throws Exception {    
           
            throw new NumberFormatException(" " +
                    "Test ControllerAdvice randomException[" + "NumberFormatException" + "]");
    
            [...]
        }
    
        @RequestMapping(value = "/mavException", method = RequestMethod.GET)   
        public ModelAndView modelAndViewException(Authentication auth, HttpServletRequest request) throws Exception {  
         
            throw new UnexpectedRollbackException("Test ControllerAdvice Exception for mav");
            [...]
        }
    }
    
  3. Write ONE new Controller, this will act as your ControllerAdvice controller. Notice:
    • the class is annotated with @ControllerAdvice
    • @ExceptionHandler is annotated above your generic "handleException" function
    • handleException function takes generic Exception e as a parameter
    • it checks the accept header to see how the controller function was invoked (via ajax or via form submit; randomException or mavException, respectively).  *Update*  We have to check for null first in case the request doesn't specify a response type expected.  If the request doesn't specify it, then simply return text/html.
    • It returns json or html
    • @ControllerAdvice
      public class CherryShoeControllerAdvice {
      
          /*
           * Handles JSON and HTML
           */
          @ExceptionHandler
          @ResponseBody
          @ResponseStatus(HttpStatus.BAD_REQUEST)
          public String handleException(HttpServletRequest request, HttpServletResponse response, Exception e) throws IOException {    
              String acceptHeader = request.getHeader("Accept");
             
              // If Accept header exists, check if it expects a response of type json, otherwise just return text/html
              // Use apache commons lang3 to escape json values
              if(acceptHeader.contains("application/json")) {
                  // return as JSON
                  String jsonString = 
                          "{\"success\": false, \"message\": \"" + StringEscapeUtils.escapeJson(e.getMessage()) + "\" }";
              
                  System.out.println("In handleGeneric" + e.getMessage());
                  return jsonString;
              } else {
                  //return as HTML
                  response.setContentType("text/html");
                  return response.toString();
              }
          }
      
      }
      

BTW - if you wanted to specify each type of exception going to a separate @ExceptionHandler you could.

BTW - The main cons for using pre-Spring 3.2 @ExceptionHandler (http://docs.spring.io/spring/docs/3.1.x/spring-framework-reference/html/mvc.html#mvc-exceptionhandlersby itself are you have to:

  • Define an ExceptionHandler for EACH controller (or have each controller inherit from one common base)
  • Define EACH exception type to be handled – Or have each controller throw the specific type of exception expected


Saturday, August 31, 2013

Wonky UI behavior when including multiple jQuery libraries

We use blockUI in our web application to prohibit user interaction in a couple scenarios, particularly when making ajax calls.  There was strange behavior where whenever the blockUI was invoked, it didn't block the UI until the ajax call returned!

Here's what I did in my investigation to find out why:

  • Just to confirm the blockUI library worked, I created a simple webapp example, where I only included the latest blockUI library and latest jQuery libary.  Calling blockUI directly prior to the ajax call, and then unblockUI after; everything worked great.  
  • After that was confirmed, brought this simple example into the actual web application, things went wonky.  The actual web application has all sorts of jQuery libraries (jQuery base, jQuery tools, jQuery ui, etc), so something with the javascript libraries was causing an issue.
  • I thought perhaps the specific attributes of the jQuery.ajax calls weren't proper (i.e. asynch was false when it should have been true).  Confirmed this was not the case when bringing the same ajax call in a simple JSP file in the actual web application.
  • Did a search in the code base and found not one, not two, but THREE versions of jQuery base library in the system!  Three files were named jQuery.js, jQuery1.8.0.js, and jQuery1.9.1.js.  And on top of that, the jQuery tools library had jQuery 1.4.2 embedded inside of it!)
  • Created a breakpoint in the browser developer tool, watched $.fn.jQuery; and saw that indeed we were using jQuery 1.4.2 library.  This confirmed that the jQuery library embedded in the jQuery tools library was "The Winner" (not any of those other THREE jQuery libraries in the code base!)
  • Just to confirm the blockUI library worked with jQuery 1.4.2, I commented out references to those aforementioned THREE libraries.  I reverted back to an older version of blockUI (2.42) that only needed jQuery 1.2.3 or later.  Calling blockUI directly prior to the ajax call, and then unblockUI after; everything worked great.

Conclusions from this case study?

  • Using jQuery 1.4.2, and blockUI 2.42 worked fine!  Since jQuery was included multiple times in the code base, weird behavior occurred (even though you would think the latest js include would "override" the ones included above it - NOT TRUE)
  • Calling blockUI can be configured with fadeIn of 0 (as to not delay the blockUI overlay from being displayed)
  • The jQuery ajax must be asynchronous (synchronous will freeze the browser).  This is discussed in this stackoverflow article.
  • Do not include multiple versions (or even the same version multiple times) of jQuery javascript library or you will eventually get strange behavior

The key ideas I gathered from this is a common problem:

  • There are all sorts of problems that occur when there are conflicting dependencies in libraries that are used (jQuery, java, etc).
    • Developers chasing phantom bugs
    • De-stabilitzation of the application
    • etc.
  • Every "once in awhile", you need to do an analysis of what libraries (UI or backend) and dependencies have been introduced to the system.  Or as new libraries become available, you may also need to do this analysis to determine if you want to upgrade or not

TODO: I plan to look into requireJS for jQuery, which is a javascript library and module loader that only loads js files as needed.

Sunday, February 17, 2013

Cross-domain AJAX calls with JSONP


It's a common issue to have a web application running on a server that needs to make a web service call to a service running on another server. There are a couple of solutions to that:
  1. Make a direct HTTP GET call with server side code to the service:  
    • Pro: No special processing of the JSON return data: make the HTTP GET call, process the JSON response, display the data
    • Con: This is limited, as the page being returned is static
  2. Make an AJAX call with client side code to the service:  
    • Pro: Dynamically make the service call based on user interaction
    • Con: The application needs to have specialized handling to make the cross-domain AJAX request
For this discussion, we'll look deeper at the second bullet and explore the solution further.

Cross-Domain AJAX calls with JSONP
Without properly setting things up to make cross-domain AJAX calls, you might see the following if using Firebug.  You might see the following and wonder what the heck is going on?
  • Firebug shows a HTTP OK 200 response, which makes it appear that the call was successful.  But on closer inspection, there's no data returned in the response...
  • Firebug shows that data was returned, but it says the JSON is invalid.  When checking the JSON data in jsonlint, it's perfectly valid JSON!
JSONP (JSON with padding) can help us implement this more appropriately, but there are a couple of caveats:

Caveat 1: You have to be in control of the web application that is making the AJAX request:
    • That is because you need to specify to the web service that you want to wrap the response as JSONP.  
    • If using jQuery (since version 1.2), you can load JSON data located on another domain if you specify a JSONP "callback" URL parameter.
/webapp/service/com/blogspot/cherryshoe/docList?id=06022012&callback=?

Caveat 2: You have to be in control of the web service that is being called:
    • That is because you need to look for that optional "callback" parameter; if it's available, wrap the response as JSONP.
    • If using jQuery, jQuery will automatically assign the "callback" parameter a value, in this case it was "jQuery16406082620163990349_1361055846009", the web service will wrap the JSON response with that value, making it JSONP.
jQuery16406082620163990349_1361055846009
(
    {
        "status" : true,
        "statusMessage" : "Retrieved 2 documents for id: 06022012",
        "totalRecords" : 2,
        "documents" : 
        [
        {
            "docId" : "1234",
            "docName" : "06022012_1.pdf",
            "docType" : "1"
        },
        {
            "docId" : "5678",
            "docName" : "06022012_2.pdf",
            "docType" : "2"
        }
        ]
    }
)

Obviously there may be security considerations if the web service or web application is not public.  This article helped a lot when I was researching this issue.

Saturday, August 25, 2012

HOW TO: Make file uploads work with WizardPro jQuery Library and Spring MVC 3.0


My web application front-end code is built using HTML5, CSS3, and jQuery, using the Spring MVC 3.0 Framework to get back-end data back to the browser. We use the WizardPro jQuery library to aid the user in creating objects in the webapp (WizardPro is a great little jQuery library that enables you to create an object in a few steps).

Here is where my heartache comes in – WizardPro’s default form submit uses XMLHttpRequest. Don’t get me wrong, most of the time the default behavior works great! Specifically, it doesn’t work is when you need file uploads in your web app, therefore requiring an input type of file as a form control. Luckily, Spring MVC 3.0 fileupload support was available in our toolkit already (it provides a MultipartResolver for use with Apache Commons FileUpload). To be able to make file uploads work with WizardPro and Spring MVC file upload, you must do the following:

1.  For the Spring MultipartHttpServletRequest to work, set WizardPro’s  defaultAjaxRequest attribute to false when the wizard is instantiated.
$("#wizard").wizardPro({
defaultAjaxRequest: false
,...
});
2.  WizardPro uses a default form class called .defaultRequest, this makes sure the plugin handles the default form ajax requests submits and validation.  Make a copy of the .defaultRequest CSS classes and name it uniquely, i.e. .defaultRequest2.  In the form tag, set the class to this new class name, so the class will not bind wizardPro to use default ajax submits.  Instead WizardPro will use normal HTML form submits with the file input form control for file uploads.

BAD:
<form class=”defaultRequest” action=”someUrl” method=”post” enctype=”application/x-www-form-urlencoded”>

GOOD:
<form class=”defaultRequest2” action=”someUrl” method=”post” enctype=”multipart/form-data“>

3.  Set the encode type to multipart/form-data in the form tag, MultipartHttpServletRequest filter expects this.  Example in number 2 above.

When you follow the above steps, along with setting up Spring MVC’s multipartResolver in the servlet context spring configuration file, ensuring the form action URL and the controller @RequestMapping match, etc, then WizardPro and file uploads work great together!

P.S.  You may ask me, “Why not use an HTML5/AJAX supported file upload library?”.  Uploadrr is a great little library that does this, and I’ve tested it using Firefox 3 and Chrome 10, with both @RequestParam using MultipartFile and also with the HttpServletRequest Input Stream to get the file byte data.  Unfortunately, it does not work for our primary browser platform, IE8, which is why (for now at least), we can’t integrate this into the webapp.