Do you ever go into a project with it all mapped out in your head? You’ve got every twist and turn of the code written before you’ve ever sat down to type a line. How many times does it actually work out like that? That was me entering this project. We have a partner who needed to access one of our data stores. We told them we’d build them a custom solution to take advantage of this so I decided I’d develop a nice cross browser friendly application in AJAX that they could drop onto their site which would call these XML files on our servers. It seemed simple enough on the surface.

I put together some quick sample code to get a proof of concept rolling only to hit a wall right out of the gate. My old nemesis, Same Origin Policy, code blocked me from accessing the XML since the file was on a different server than the processing code. Basically, Same Origin Policy prevents you from accessing a file, like our XML data, when you are calling it from a remote server. Its a security mechanism designed to keep the script kiddies from doing harmful javascript injections on your site. Start injecting some AJAX code, and the serious fun begin.

So how can we make these cross domain data calls if the default mechanism within Javascript is setup to thwart us at our every turn? There are a few different options, but the one I choose to pursue transforms our data over to JSON and utilizes a PHP Proxy to talk with our AJAX code.

While I would have preferred to work in XML, since I’ve worked with more XML code over the years than I care to admit, JSON isn’t a bad alternative. While its format is a syntactical departure, its spirit is one in the same with XML. Updating my data routines to encode the new files in JSON was a snap. Here is a sample file:

1
{"events": [{"city": "Duluth, GA", "date": "7/2/2014", "url": "evtid=22697"},{"city": "Atlanta, GA", "date": "7/4/2014", "url": "evtid=22697" }]}





If you haven’t worked with JSON before, I suggest running your JSON code through a validator so you can make sure you are passing files the remote server can read. Just like with XML, a stray bracket or comma can throw the whole thing in the garbage. While we are discussing tools, I also highly recommend opening up javascript error handling in your browser of choice. WordPress has assembled a pretty detailed explanation of how to do this depending on your browser. Javascript errors will serve you up a blank page with no clues as to where you went wrong. Tools like these are critical to timely and “not chunking your computer out the window” development.

Now that we have our data in a format that we can pass across, let’s take a look at our PHP proxy. You can think of our proxy as a web service. It is functioning as the go between, allowing the two star crossed domain servers to talk with one another. It is a painfully simple little file (see below). We set the header content type to javascript. For this instance, I’m passing in the file name as a querystring parameter (a) then serving it up to the inquiring server through $_GET[‘callback’].

proxy.php

1
2
3
4
5
6
7
<?php
header("Content-type: text/javascript; charset=utf-8");
$c = $_GET['a'];
$s = file_get_contents('http://yourdomain.com/json/' . $c . '.json');
header("Access-Control-Allow-Origin: *");
echo $_GET['callback'] . '(' . $s . ');';
?>

I mentioned that I changed my data generating routine to produce JSON files instead of XML. In reality, I could have accomplished the same thing through the proxy. If I had replaced the last line with these two instead, it would have waived the magic wand over those XML files until they became JSON:

1
2
$a = json_decode(json_encode((array) simplexml_load_string($s)),1);
echo $_GET['callback'] . '(' . json_encode($a) . ');';

Now we get to the meat of our little app — actually putting all of the pieces together by calling the JSON via the proxy with AJAX. I’ve tweaked our original implementation to instead serve up details of metro area 5K races (full code implementation is outlined at the bottom of this section). Looking at the code below after we’ve included our jQuery libraries, we set the city we want to get the JSON file for.

Digging a few lines into the code you’ll discover where we make our call to the PHP proxy file:

1
2
3
type: "GET",
url: "http://yourdomain.com/json/proxy.php?a=" + sCity.replace(/ /g,"-") + "&callback=?",
    dataType: "json",

Notice, we are passing in the city via the querystring so the proxy knows which JSON file to serve up. Since we feasibly could hit cities without races, I included a check to see if we had an empty file before we started to swing through the JSON nodes.

1
2
3
    if (jQuery.isEmptyObject(data)){
      $("<li></li>").html("<div class="location">No 5K Races are Currently Available.</a></div><div class="clear"></div>").appendTo("#dvContent ul");
    }

Once we’ve decided that we have JSON data to process, we call our each method to loop through the JSON elements.

1
$.each(data['events'],function(){

There are a few things to notice once we get within our each loop. I have this line commented out, but it was helpful in testing to see if the JSON data was correctly getting passed across. Since its returning an object, we have to run it through the stringify method to actually see what the data is. Having it pop up in an alert is a handy way to get to this.

1
alert(JSON.stringify(data));

I also have times where I only want to show the top X races so I’ve wrapped the data pull within an if conditional so I can limit the output to the top 5 when needed. For readabilities’ sake, I’ve pulled out the JSON values on each cycle through the loop into their own variable, then I spit them out to the page within div tags which gets prettied up by our stylesheets.

1
2
3
4
5
6
      var sDate = this.date;
      var sCity = this.city;
      var sUrl = this.url;
      sDate = sDate.slice(0, -5); // shortens the date by removing the year
 
    $("<li></li>").html("<div class="date">" + sDate + "</div><div class="location">" + sCity + "</div><div class="link"><a href="http://youdomain.com/RaceDetail?" + sUrl + "" target="_blank">Details</a></div><div class="clear"></div>").appendTo("#dvContent ul");

Full AJAX Code File

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
<html
<head>
<script src="//code.jquery.com/jquery-1.10.2.js"></script>
<script>
//Code Starts
var sCity = "Atlanta";
$(document).ready(function(){
  $("#dvContent").append("<ul id="schedule"></ul>");
  $("#dvCity").append(sCity + " 5K Road Races");
  sCity = sCity.toLowerCase();
  $.ajax({
    type: "GET",
    url: "http://yourdomain.com/json/proxy.php?a=" + sCity.replace(/ /g,"-") + "&callback=?",
    dataType: "json",
 
    success: function(data){
    // check to see if we have races available - display custom message if not 
    if (jQuery.isEmptyObject(data)){
      $("<li></li>").html("<div class="location">No 5K Races are Currently Available.</a></div><div class="clear"></div>").appendTo("#dvContent ul");
    }
    else{
    $.each(data['events'],function(i,row){
    //alert(JSON.stringify(data));
    // if we only want to display a set number of dates, uncomment next three references
    //if (i<= 5){
      var sDate = this.date;
      var sCity = this.city;
      var sUrl = this.url;
      sDate = sDate.slice(0, -5); // shortens the date by removing the year
 
    $("<li></li>").html("<div class="date">" + sDate + "</div><div class="location">" + sCity + "</div><div class="link"><a href="http://youdomain.com/RaceDetail?" + sUrl + "" target="_blank">Details</a></div><div class="clear"></div>").appendTo("#dvContent ul");
    //}
    });
    // if we are shortening results, open this line up to link over to the full race page
    //$("<li></li>").html("<div class="location"><a href=" http://youdomain.com/RaceDetail?" target="_blank">View All Race Dates</a></div><div class="clear"></div>").appendTo("#dvContent ul");
  }
  },
  error: function() {
    alert("Error tripped");
  }
  });
});
//Code Ends
</script>
 
</head>
<body>
    <form id="form1" runat="server">
<div id="mywidget">
<h2><div id="dvCity"></div></h2>
    <div id="dvContent"></div>
    <div class="clear"></div>
</div>
<link href="widget-style.css" rel="stylesheet" type="text/css" />
    </form>
</body>
</html>

Now hopefully I’ve ferreted out all of the errors you might run across, but I thought I might mention a few that I stumbled over just in case you might see the same during your testing.

Uncaught SyntaxError: Unexpected token o
In an earlier draft of the code, I was trying to do a JSON.parse within our each method. Since we’d already done this, I could just delete this line of code and go along my merry way.

unexpected token illegal
For me, this error was triggered when I pulled in the JSON file as a multi-lined string and assign it to the js variable. That won’t fly so as soon as I took out those line feeds, everything fell into line.

resource interpreted as script but transferred with mime
This one went back to our proxy file. When I didn’t have the content type properly set as application/javascript, the program threw this red card at me.

So I hope people find this helpful. I couldn’t find anyone online who had an example of exactly what I was looking for. I had to piece together code from 40 or so different articles to come to this solution. It isn’t difficult, but it does take a little tinkering with. Once you have the pieces singing in harmony, the implementation is a beautiful thing. Happy coding!