The whole point to writing the Wiki Text jQuery plugin was so that I could use it on the Thistle Society web site to enhance the description text from Google Calendar events shown on the Events page.
So, I was a bit irritated that it didn’t work when I tried it.
Most of it turned out to be pretty basic errors – the wrong filename, typing errors and the like, but one issue seemed determined to make my life a misery.
For some reason an irritating little piece of JavaScript that used to work was causing annoying problems.
Some Background
The JavaScript (my first serious attempt at using JavaScript and jQuery) uses jQuery+Ajax to retrieve a Google Calendar feed in Atom format.
I use jQuery to parse the XML and then, quite scruffily, extract various bits of data from it to build the list of events.
However, for some reason, a few of the elements I need to get data from include an XML namespace prefix, “gd:”. The resulting code is shown below with most of the irrelevant bits remove.
function handleCalendar(xml) { var feed = $("feed", xml); ... $(feed).children("entry").each( function() { // This worked fine... var eventTitle = $(this).find("title").text(); /// This didn't! var startDateStr = $(this).find( "gd:when" ).attr( "startTime" ); }); ... } $(function() { $.ajax( { type : "GET", url : "events-feed.php", dataType : "xml", error : function() { alert("Failed"); }, success : handleCalendar }); });
As you can see, the “title” element was no problem, but the “gd:when” element wasn’t found. Fiddlesticks! (I try to keep it clean here…)
The first time around I found a method which worked – it was to use the expression “[nodeName=gd:when]” instead. This was fine and worked in all browsers I tried.
The Problem Returns – Worse!
I was a bit miffed, therefore, when I updated the JavaScript to use the latest version of my Wiki Text plugin and it stopped working.
It took ages to find the problem and fix it – and only afterwards did I work out what the actual cause was.
While updating the web page template, I had updated it to use a CDN hosted version of jQuery – and at the same time moved from version 1.4.3 which I had copied locally to the site to version 1.5.2.
It appeared that this newer version didn’t support the “[nodeName=gd:when]” syntax – and that was causing the errors.
The Solution
I found a solution which appeared to resolve the problem. A Stack Overflow posting had asked a similar question (http://stackoverflow.com/questions/128580/jquery-find-problem) and used an escape syntax to find the element – “gd:when”.
This worked and so I finished updating the code and rebuilt the local staged site for testing. I tried it on IE 9 and Firefox 4 without a problem.
But then I tried it in Chrome. Oh. It seems that the syntax above doesn’t work in Chrome.
Back to the drawing board.
A Better Solution
Not beaten, I resorted to the approach foisted upon all JavaScript developers by the painful differences between each manufacturers browsers; try one way and if it doesn’t work, try another.
After a couple of attempts trying different combinations, I hit upon the following approach:
// Need to work out how to handle namespaced prefixes on some // elements. var prefix = "gd:"; // Most prefer this... var startDateElement = $(this).find( prefix + "when" ); if( startDateElement.length == 0 ) { prefix = ""; // ...but some don't! startDateElement = $(this).find( prefix + "when" ); }
It worked! The prefix is declared to include the namespace and escaped colon. If it works, fine, otherwise the prefix is emptied and we try again. The prefix can then be used for any other elements with the namespace.
In the Stack Overflow article I mentioned, there is a way to check the namespace if required – and I’m sure the approach can be extended to handle multiple namespaces.
So that is how the final version works. I still need to find time to tidy up the rest of the code – the date handling is a mess and I could make better use of the jQuery element construction features, but it works.
Final note – if you find any problems using this in other browsers, let me know. Thanks.
Apparently, I escapes the colon with double backslashes like this to make it work:
var prefix = “gd\:”; // Most prefer this…
Thank you for this solution, it works. You saved my day, man/
Great stuff, thanks.
Simon, thank you! Really easy and good solution. You saved a lot of my time)))
I put it in a function:
function XMLfind(prnt, pref, namestr) {
var prefix = pref+”\:”;
var nametag = $(prnt).find(prefix + namestr);
if (nametag.length == 0) {
nametag = $(prnt).find(namestr);
}
return nametag;
}
and use it like this:
var name_text = XMLfind(this, “d”, “test_name”).text();
I tested it in IE, Chrome, Opera, Android browser – works fine. But in Opera Mini (on Android) it does not work. Moreover the tags without colon also cant be find even by $(xml).find(‘entry’). Is another way for opera mini?
I am new to web development and JQuery, and using this solution has gotten me a lot closer to a working application, but an unanswered (and maybe obvious) question arose. How do you get the startDate or endDate values from the gd:when?
When I use $(this).find(prefix + “when”) and then print it out, it displays as [object Object]. I take this to mean that it is returning the gd:when node which has 2 parts to it: startDate and endDate.
I also tried using .attr(“startDate”) appended on the end, but that doesn’t work.
What am I missing?
The very next line in my script is
var startDateStr = startDateElement.attr( "startTime" );
You can see the full script in “events.js” on the page at http://localhost/www.thistlesociety.org.uk/events.html.
Perhaps try tracing it through with Firebug or IE’s F12 feature.
JS NOOOB, your missing this:
.text();
eg:
========
// Need to work out how to handle namespaced prefixes on some
// elements.
var prefix = “gd:”; // Most prefer this…
var startDateElement = $(this).find( prefix + “when” ).text();;
if( startDateElement.length == 0 )
{
prefix = “”; // …but some don’t!
startDateElement = $(this).find( prefix + “when” ).text();;
}
========
But still It doesn’t work for me in Chrome 17.0.963.66, the example by exactsolutions is a nice one. This appears to be the best way, but still no joy for me… will try updating jQuery.