Archive for the “JavaScript” Category

I’m guessing that if you are reading this post you have already encountered the problem of the same origin policy with regards to retrieving data with AJAX from urls in other domains than your’s (the requesting domain). This policy, enforced by browsers, means you cannot fetch raw data from other domains with straight AJAX calls.

The Problem I Was Trying To Solve (skip this paragraph if you just want the solution)
Here’s the situation I ran into. At work, we have a timesheet entry program running on one subdomain, and Flyspray (bug-tracking software) on another subdomain. We wanted to get task descriptions from Flyspray integrated in our employee timesheet notes. Basically, the employee types a Flyspray task # for a given task they are working on, anywhere in their timesheet log entries. A jQuery script then converts that task # into a link to the task. In addition, that same script lets the user just hover over the task # to see a summary description of the task. When they hover, jQuery fires an AJAX request to a PHP script on the Flyspray subdomain. I couldn’t get it to work, so after researching it on jQuery sites I discovered my need for JSONP.

JSONP Circumvents the Same Origin Policy
Data returned from an AJAX call in JSONP (JSON with padding) format is designed to solve this problem. In jQuery, you can specify that you want either JSONP or JSON data returned from your AJAX calls. The differences between the expected returned formats of JSONP and JSON data are as follows:

  • JSON returns a JSON-formatted object only. For example: { "id" : "mydomelementid", "message": "This data came from a server!"} . This is a JSON object with 2 properties, id and message, and their corresponding values. See json.org to find out more about JSON.
  • JSONP returns a JSON-formatted object wrapped inside a function call. For example: jsonp123( { "id" : "mydomelementid", "message": "This data came from a server!"}); .

JSONP works by injecting what looks like a local function call directly into your script, attaching it to a script tag (in the form of a url). Wikipedia has a great explanation of this.

jQuery makes it easy to do AJAX calls implementing JSONP. You can use the simple getJSON method, or the ajax method. I’ll show you examples using both. First, though, let’s look at some example PHP code, so you know how to code the server side stuff. This part is what was not clear to me when I started researching JSONP.

The Server-Side Code (PHP)
In our example, we want to return a JSON object with a property of “message” that contains some feedback text to show the user when they click a button.

<?php
header("content-type: application/json"); 

// Create a generic object.
// Assign it the properties of id (optional - id of target HTML element, from URL)
// and 'message' - the feedback message we want the user to see.
if (isset($_GET['id'])) $rtnjsonobj->id = $_GET['id'];
$rtnjsonobj->;message = "You got an AJAX response via JSONP from another site!";

// Wrap and write a JSON-formatted object with a function call, using the supplied value of parm 'callback' in the URL:
echo $_GET['callback']. '('. json_encode($rtnjsonobj) . ')';    

?>

This script returns a string in JSON-formatted object notation, wrapped in a function call. The name of the function comes from the URL parameter ‘callback’. The JSON object has one expected property (“message”) and one optional one, “id”. You provide the “id” parameter value on the URL string, also. I’ll explain its use in the second jQuery example. So, let’s say we call our script jsonp.php. The url to call it could look like this: "http://www.example.com/jsonp.php?callback=jsonp123". What json.php writes back to the server will be: json123({"message": "You got an AJAX response via JSONP from another site!"}); . If this were a JSON call instead, we’d omit – json123(); – the function call wrapper.

(Note our PHP script creates an object on the fly, without declaring a class and instantiating one. Our object is an instance of the stdClass class, a generic PHP object. Just assigning a property to it: $rtnjsonobj->;message = "You got an AJAX response via JSONP from another site!"; achieves this. The json_encode function then converts the PHP object to a JSON-formatted string. )

The Client-Side Code (jQuery)
I’ll show you 2 examples using jQuery AJAX functions to get the message produced by jsonp.php. The first example uses the typical jQuery anonymous callback function programming pattern. The second uses a named callback function.

Example 1

$(document).ready(function() {
 $("#jsonpbtn").click(function() {
	var surl =  "http://www.fbloggs.com/sandbox/jsonp.php?callback=?";
	var me = $(this);
	$.getJSON(surl,  function(rtndata) {
		me.feedback(rtndata.message, {duration: 4000, above: true});
    });
 });
});

This example is the simplest implementation of JSONP with jQuery. It calls our PHP script jsonp.php, passing a single parameter on the URL – callback=?. This specific syntax is the key to this being considered a JSONP AJAX call, rather than a JSON call. Note that the method is still getJSON- not getJSONP. The callback=? convention tells jQuery to generate a random function name and pass that as the value of the parameter named callback. Recall that our PHP script gets this function name with $_GET['callback'] , so we don’t have to worry about the actual generated name. Then, the anonymous function call (the second option on the getJSON method) does the work. In this case, it references the jQuery object that was clicked (the variable me) and calls my feedback plugin to display the message text. The fragment rtndata.message means ‘get the message property of the object rtndata (the JSON object returned by our PHP script). Feedback simply displays the message above the clicked button, for 4 seconds.

Example 2
This example uses a named callback function. Note that this capability is only supported in jQuery 1.4, so make sure you have the latest and greatest installed. As of this post, I’m using 1.4.2. I’m not sure why you would want to use a named callback function, other than to conform to DRY. The jQuery docs mention obliquely that you might want to cache your AJAX responses, but they give no explanation of how or why. Anyway, I thought it was worth trying, so here it is:

$(document).ready(function() {
$("#jsonpbtn2").click(function() {
	var surl =  "http://www.fbloggs.com/sandbox/jsonp.php";
	var id = $(this).attr("id");
	$.ajax({
		url: surl,
		data: {id: id},
		dataType: "jsonp",
		jsonp : "callback",
		jsonpCallback: "jsonpcallback"
		});
 });
}); 

// Named callback function from the ajax call when jsonpbtn2 clicked
function jsonpcallback(rtndata) { 

	// Get the id from the returned JSON string and use it to reference the target jQuery object.
	var myid = "#"+rtndata.id;
	$(myid).feedback(rtndata.message, {duration: 4000, above: true});
}

In this case, we can’t use the shorthand getJSON method, because it doesn’t have enough options. Instead, we must use the longer form ajax method. No big deal.
Here’s what’s going on. First, note the URL does not contain the callback=? parameter. Instead, we use the options jsonp and jsonpCallback, which is like writing: "jsonp.php?callback=jsonpcallback" for our url. Next, we pass the id of the DOM element (button) we clicked, as another parameter on the URL. Recall that our PHP script looks for this, and if it finds it, sends it back as a property of the returned JSON object. Next, we specify the expected data type returned from our server-side script (JSONP).

The cycle of code execution for this example is:

  • User clicks button with id of jsonbtn2
  • The browser invokes the $.ajax() method
  • The AJAX call invokes the server-side script, jsonp.php
  • jsonp.php gets the button’s id from the url parameter, constructs a JSON object with id and message properties and writes it back to the browser
  • The browser responds by running function jsonpcallback. It expects one parameter- our returned JSON object.
  • jsonpcallback retrieves the clicked button’s id from the returned JSON object, constructs a valid jQuery selector with it, and calls the feedback plugin to display the message above the button, just like in the simpler anonymous function example.

You should now understand why we pass the id back and forth. We need it in order to keep track of which element we are acting upon. We didn’t need to do this in the first example because of the magic of closures, another big topic.

That’s it!

See The Examples At Work
I’ve posted this page to show you working examples. You can view source if you want to see the jQuery code. It should be identical to what I’ve posted.

Considerations When Using JSONP
JSONP relies on injecting a script tag into your page. A side effect of this is that if you have errors in the data returned by your server, you won’t see any errors- the script tag just fails silently. An example of an error might be an incorrect callback function name (only likely in scenarios using Example 2 coding pattern), or malformed JSON.

When I first tried coding this, I got a Firebug error of ‘Invalid Label’. This totally uninformative error is the result of not wrapping the JSON object in a function call. In other words, if you have existing server code that writes JSON objects, it won’t just magically work with JSONP. Your server code must wrap a function call around the object, as I’ve shown.

Because JSONP relies on the script tag, it doesn’t use the callback features of the underlying HTTPRequest object. This means the success, failure, complete callback functions on the $.ajax() method are irrelevant and nonfunctional when you use JSONP.

Tags: , , , , , , , ,

Comments 2 Comments »

I’ve written a few articles in recent years that have been published by MC Press Online, relating to IBM i topics. If you don’t know what the IBM i is (or an AS/400, iSeries or System i), you can stop reading! Here are two lists of links to those articles. The first list is general education. The second is product-specific, related to products marketed by my company. (Articles are ordered by most recent first)

Educational Articles

Product-Specific Articles




Tags: , , , , , , , , , , , , ,

Comments No Comments »

Feedback is a jQuery plugin that lets you send feedback to a user in the form of an info message or error message, associated with any page element. It uses the jQuery UI plugin to determine the default styles of the info and error messages, but you can also use your own styles. Complete details, including demo, documentation and downloads are on this page.

Tags: , , , , ,

Comments No Comments »

Firebug – debug your applications. An absolute must. Best features:
  • Debugger – step through, over, etc.
  • Console log for monitoring AJAX interactions -shows parms sent, data returned, round-trip time.

  • Web Developer – fantastic CSS diagnostic support. Best features:
    • View generated source – important if your script modifies the original DOM of your page
    • Display Element Information – shows all the properties of an element in a convenient popup. To use, press Ctrl+Shift+F or select menu Information/Display Element Information
    • Edit CSS – lets you edit the CSS selectors in real-time, and shows you the results – almost as you type
  • MeasureIt. Lets you find the height and width of any element or area of the page, in pixels. Helps diagnose CSS issues, for example, when you use combinations of margin, width, padding and border attributes.
  • Codeburner from Sitepoint, one of my favorite online journals (www.sitepoint.com). Integrates with Firebug to provide comprehensive cross-reference information on HTML and CSS. Best feature:
    • Browser compatibility tables
    Tags: , , , ,
  • Comments 1 Comment »

    Summary: Quirks of checkbox markup in HTML – differences between IE and FireFox…

    Tags: , , ,

    Comments No Comments »

    This post explains how to set a group of checkboxes to checked or unchecked using jQuery 1.3, by clicking an “All” or “None” button.

    First, let’s select our group of checkboxes. I’ve seen some fairly complicated jQuery selectors for finding checkboxes on a page, but it seems to me the easiest thing to do is just assign a common class to each one in a group, even if you don’t define the class in your stylesheets. Like this:

    <input type="checkbox" class="selsts" name="selsts" value="E"> Emailed
    <input type="checkbox" class="selsts" name="selsts" value="W"> Work in Progress
    <input type="checkbox" class="selsts" name="selsts" value="P"> Pending client call
    <input type="checkbox" class="selsts" name="selsts" value="R">R-Returned call

    the jQuery selector for this is: $(".selsts") .

    We could also select all the elements based on their common name, which I think goes like this: $(['name=selsts']) .
    But I prefer classes, because you can easily change their names without affecting server-side code that may be dependent on form field names.

    Let’s say we have two buttons on our page, using the following markup:

    Select: <input type="button" id="allsts" value="All">, <input type="button" id="nosts" value="None">

    To make all our checkboxes checked:

    $("#allsts").click(function() {
    $(".selsts").attr('checked', true);
    });

    To uncheck all the checkboxes:

    $("#nosts").click(function() {
    $(".selsts").attr('checked', false);
    });

    That’s it.

    To determine if a checkbox is checked or not, we can loop through the array like this:

    $('.selsts' ).each( function() {
    var isitchecked = this.checked;
    });

    Or, individually:

    if ($('#somecheckbox').checked == true) { blah blah ... }

    Tags: ,

    Comments 2 Comments »

    FireFox doesn’t have a native global event handler. Here’s how to create one using FireFox’s event-capturing model.

    Tags: , , , ,

    Comments 4 Comments »

    Firebug beta 1.0 is now available. This is by far the best toolbar available for FireFox or IE for debugging web applications. See This blog entry at Sitepoint for more details.  A few  of the features I really like are:

    • The debugger  – identifies exact line of script in error.
    • The HTML view – lets you view contents of externally linked Javascript files, also.
    • The CSS inspector – shows you all ancestor css rules for elements, not just the current CSS rule, so you can see the total effect of the cascade.
    • The ability to change CSS settings on the fly. For example, hover over a color, click on it, then change the RGB value to see another color – it does this for the specific area on the page, as well as in the sheet.
    Tags: , ,

    Comments 2 Comments »

    Ok, so JSON is conceptually simple. See json.org for more info. So I include json.js in a page, then attempt to reference the parseJSON method of a string object and get an error. Why? Is it because I reference the method in another external script file, instead of using inline script in the page itself? How exactly does Javascript run the code to extend the prototype of an intrinsic object? Is it prior to the page loading? Help!   BTW – I can get this working no problem in a simple page where the script is inline.

    Comments No Comments »

    I confirmed that click is not a W3C method for anchor objects. However, thanks to the prototype property of objects you can extend a host object by adding methods to it. The code below does this for anchor elements, although you could do it for any element. Credit to Martin Honnen for his article at http://www.faqts.com/knowledge_base/view.phtml/aid/9368 for the solution. Here’s the code, which just needs to be in the top of your page so that it runs prior to any scripts at document load time:


    try {
    // create a element so that HTMLAnchorElement is accessible
    document.createElement('a');
    HTMLElement.prototype.click = function () {
    if (typeof this.onclick == 'function') {
    if (this.onclick({type: 'click'}) && this.href)
    window.open(this.href, this.target ? this.target : '_self');
    }
    else if (this.href)
    window.open(this.href, this.target ? this.target : '_self');
    };
    }
    catch (e) {
    alert('click method for HTMLAnchorElement couldn\'t be added')
    }

    Comments No Comments »