Minimal event listeners with jQuery

I have a few pages on a project that use lots of buttons and event listeners. The developers that worked on this page created a single event listener for every button and every state (click, hover, mouseover, mouseout, etc). This seems to standard development practice.

But, to save 600 lines of code I created only one or two listeners using regular expressions and made up HTML tag attributes. For example, we created a video player interface for JWPlayer which included a play, pause, and stop button.

<span ref="playButton">Play</span>
<span ref="pauseButton">Play</span>
<span ref="stopButton">Play</span>

Normally most people would create an event listener for each button and their click event. But, by using the regular expression I only need to create on event listener for the page. Once clicked I can check to see what button was pressed and run a method call for that button pressed.

jQuery( "[ref$=Button" ).click(
  { 
    if ( jQuery( this ).attr( "ref" ) === "playButton" ) {
      playJWPlayerVideo();
    }
    else if (jQuery( this ).attr( "ref" ) === "pauseButton" ) {
      pauseJWPlayerVideo();
    }
    else {
      stopJWPlayerVideo();
    }
  }
);

For more than 5 click events you might want to use a switch/case statement to make it run faster and to group similar events together to run the same method.

BASE64 and JSON

I have been working on a project that requires me to make an AJAX request to a ColdFusion service that returns a BASE64 version of an image wrapped in JSON. This JSON packet is used by the client-side to populate the SRC argument of an <IMG> tag. The process was working fine most of the time. But, every once and a while the image is broken.

After doing some checking I noticed that on the client-side the BASE64 string was not the same as the server-side.  The issue was that parts of the string were being transposed. It seems that the browser(s) were thinking that parts of the string were Unicode because some images strings contained sub-strings of u+a4f7 or u+c19b.

To correct the transposing issue ended up adjusting the client-side code and the ColdFusion service. First, on the server-side I wrapped the BASE64 process in the URLEndcodedFormat()function. Second, I adjusted the client-side code to decodeURI() the string from the JSON packet.

This process resolved the issue.

Use jQuery to Change a Select Field to Different Value with the Text

At my job one of things I am working on allows the end-user to select a point on a map this changes the select fields on the page to be rebuilt and reflects the selected map point.

The issue that came up was that the map link uses string. While the ODATA service to popluate a select field uses an integer for the option taga value. But, the text in the option tag matches the link.

So, this code will show you how change the option tag of a select box if you only have the text value.

The Select Field

The filed thing needed is to build a select field. In this example we only need the text and not the value of the select options.


<label>Location</label>
<select id="alphabet">
  <option></option>
  <option>Alpha</option>
  <option>Beta</option>
  <option>Gamma</option>
  <option>Delta</option>
</select>

Javascript Function

The function below used jQuery’s $.each() to loop over all the option tag values for the select field and find the exact match. Once found we change the field option the one we are looking for and then use return false;to break out of the loop.


function changeLetter( L ) {
  $( "#alphabet option" ).each(
    function () {
      if ( L === $( this ).val() ) {
        $( "#alphabet" ).val( L ).change(); 
          return false;
        }
      }
    );
  }

Full Sample


<html>
  <head>
    https://ajax.googleapis.com/ajax/libs/jquery/1.12.0/jquery.min.js
	
      $( document ).ready(
        function() {
          $( "button" ).on(
            {
              "click" : function () {
                changeLetter( "Gamma" );
              }
            }
          );
        }
      );

      function changeLetter( L ) {
        $( "#alphabet option" ).each(
          function () {
            if ( L === $( this ).val() ) {
              $( "#alphabet" ).val( L ).change();

              return false;
            }
          }
        );
      }
    
  </head>
  <body>
    <label> Location </label>
    <select id="alphabet">
      <option></option>
      <option>Alpha</option>
      <option>Beta</option>
      <option>Gamma</option>
      <option>Delta</option>
    </select>

    <button id="changeToGamama">Change Select Option to Gamma</button>
  </body>
</html>

JSON data wrapping

While working with a development team on a RESTful solution I start proposing wrapping the service response/output in another object. This would allow us to write some META data about the response.

This META data would help developers with understanding what was going on with their request and the response provided by the service. A kinda talk back method to AJAX or REST responses.

A lot of people would say why would you need this? Well maybe you have a service that is open to the public like Twitter. You want developers to be able to access your service and understand your data without them calling or emailing you all the time. Maybe your information is labelled or structured differently than theirs. The META data provided in the wrapper would allow them to determine how to interpret the information to suit their needs.

Wrapper structure sample:


{
  "statusCode" : 1000,
  "requestID" : "63D62A09-AA1F-88CF-E890EDBF000F4F8E",
  "data" = {
    "message" : "Success", 
    "totalRows" : 1, 
    "columns" : {}, 
	"results" : []
  },
  "eventName" : "",
  "requestParams" : {}
}

Elements/Attributes of the wrapper

Path Notes
statusCode This status code is used to denote what is going on with the service or method being accessed.It is different from that of the Header status or AJAX request status.

These values can be set to reflect your status indicators.

requestID The requestID is optional and has many possible uses.First, it can be used to let developers know that the response is not cached.

Second, if you are keeping a log of requests for security, debugging, or user statistics this value will come in handy. Developers could submit a bug with the JSON packet that they received. This could help you debug possible issues with the data they supplied the service.

data This is where we would store data that the developer might want to display to end-users.
data.message The message field allows the service to send text or human messages back to end-user or developer. This message can be related to the numeric status indicator or independent.For example, say that the developer was making a request to log in. The statusCode could be 5000 letting the developer know that the method is working correctly. But, the was an error. The message element would hold the server response Password is not correct.

These messages can be handing in notifying the user of bad/missing parameters or with debugging of where the service broke.

data.totalRows This is an optional element. It is here to help the developer display the number of records being returned.
data.colmuns This is a optional element. I sometimes use it to display the column names of the query and denote if the column is a string, integer, boolean, array, UUID, GUID, or date.This helps the developer know you are returning 1 or 0 for a boolean response. And not for a number count.
data.results This is where you would normally store all the data that would be displayed to the end user.
eventName This element is used to help the developer verify that the are accessing the right method.

I normally user the path to the service. /com/members/readMembers/

requestParams This array would list all of the parameters that were sent as part of the request. This helps the developer debug responses.

Full structure sample


{
  "statusCode" : 1000,
  "requestID" : "63D62A09-AA1F-88CF-E890EDBF000F4F8E",
  "data" = {
    "message" : "Success", 
    "totalRows" : 3, 
    "columns" : {
      "productID" : "UUID", 
      "title" : "string", 
      "price" : "integer", 
      "availableUnits" : "integer"
    }, 
    "results" : [
      {
        "productID" : "502AD47D-05C6-4A47-9DD11458B8211EEB", 
        "title" : "Dell Inspiron 15 15.6\" Laptop Computer - Black", 
        "price" : 229.99, 
        "availableUnits" : 24
      },
      {
        "productID" : "93E84FE4-5367-4DD3-87F15C6A862ADA11", 
        "title" : "AOC e2252Swdn 22\" LED Monitor", 
        "price" : 99.99, 
        "availableUnits" : 102
      },
      {
        "productID" : "605C7476-7673-4C62-9E506D4331E03AAE", 
        "title" : "Apple iPad mini 16GB Wi-Fi Space Gray", 
        "price" : 259.99,
        "availableUnits" : 0
      },
    ]
  },
  "eventName" : "/com/products/resaleProducts/",
  "requestParams" : {
    "isSaleItem" : 1
  }
}