views:

49

answers:

2

I'm trying to recreate the Gmail 'star' favourite button using AJAX. Unfortunately what I have isn't working and I can't work out why.

I have the following in my HMTL:

<img id="item_1" src="/_images/star_off.gif" onclick="updateStar(this.id)" />
<img id="item_2" src="/_images/star_off.gif" onclick="updateStar(this.id)" />

And I'm using the following Javascript in a seperate file:

function updateStar(id) {
    var imgsrc = (document.getElementById(id).src == "/_images/star_off.gif") ? "/_images/star_on.gif" : "/_images/star_off.gif";
    var sendId = id.split('_')[1];
    var sendStar = (imgsrc == "/_images/star_off.gif") ? false : true;
    var objXml = new XMLHttpRequest();
    var datasource = "favourite.php";
    var params = "id=" + sendId + "&star=" + sendStar;
    objXml.open("GET", datasource + "?" + params, true);
    objXml.onreadystatechange=function() {
        if ((objXml.readyState==4) && (objXml.status==200)) {
            alert('status changed.');
        }
    }
    objXml.send(null);
}

The script favourite.php sets inserts the id into a favourites database table (or removes it if star == false).

I can't see what is wrong here but it isn't working. I've also tried the suggestions on http://stackoverflow.com/questions/2563094/jquery-gmail-star but they wont work either. Any suggestions?

A: 

I'd check to see if the Xml Http Request is even firing, and if so, what value does it hold when it does. If you have the Safari browser, you can use the Web Inspector to see this. Under Web Inspector, go to Resources/XHR, and click on the url path that corresponds to the path you set in your ajax call. Then click on the Content tab and look at the output there. If it's blank, then you know the ajax call is failing. If it has a value, make sure it's the value you expect.

Dylan West
Most modern browser has some debug tool available. For Opera there is Menu > Page > Developer Tools > Opera Dragon Fly. For Firefox you can download Firebug. Even IE has its Tools > Developer Tools. The latter has no network profiler though, but if you download Fiddler Web Debugger, you should be able you to inspect all of your HTTP traffic.
Ivar Bonsaksen
+1  A: 

Though it's hard to see where the problem is if you don't tell exactly what it is that's not working (e.g., the XMLHttpRequest call is never made, the final readyState or status are not reached), I see some flaws in your code. E.g., look at

var imgsrc = (document.getElementById(id).src == "/_images/star_off.gif") ? "/_images/star_on.gif" : "/_images/star_off.gif";

Here you're testing what the current status of the star is depending on the src property of the image. A quick test revealed that in Firefox 3.6.8 the src property contains the full URL of the image source, including protocol, domain and full path. So, in my test, the condition

(document.getElementById(id).src == "/_images/star_off.gif")

will always evaluate to false, always setting imgsrc to "/_images/star_off.gif" (so this function will never turn on the star).

A few lines later, you're testing the exact same condition again:

var sendStar = (imgsrc == "/_images/star_off.gif") ? false : true;

Try to avoid this kind of redundancy (e.g., using a boolean from the beginning); that will probably lessen the chance of introducing bugs. Moreover, in this case, the conditional operator (? :) is not necessary at all; this line could be rewritten to

var sendStar = (imgsrc != "/_images/star_off.gif");

but, as I said, try to avoid these kind of string comparisons to check the state of those stars.

IMHO, it's neater to either use two separate functions that turn on and off your star, so there's no need to test this at all, or send the state using a parameter, e.g.

<img id="item_1" src="/_images/star_off.gif" onclick="updateStar(this.id, true)" />

where true will turn on the star.

And of course it's neater to bind an event within your JavaScript (or even only show the star using JavaScript, so it's not shown when JS is unavailable).

Marcel Korpel