I'm working on an add-on for Firefox using the SDK (previously known as Jetpack).
In my add-on I need to access some data via JSONP requests to a PHP script on a remote server (which I'm in control of), and then use the data returned from the server to update certain web page elements.
In my main.js file I use a page-mod and contentScriptFile to inject a copy of the JQuery library, and my own javascript file into the web page. My javascript file uses JQuery's "$.ajax" function to access the remote PHP script.
The problem: the responses are never received.
I stumbled across this StackOverflow question, which deals with the same issue: error in jsonp call ONLY FROM firefox-extension
I've followed some of the advice there, and changed my $.ajax request by specifying my own callback, and added the callback function to my file using "unsafeWindow.callback" - I don't fully understand what's happening, but it seems the "window" reference acquired by JQuery is not the the same as the real underlying window object (I thought this sort of thing was meant to be handled invisibly by the XRayWrapper, so confused about that).
That's OK. I get a single parameter passed to my callback (I've labelled the parameter "data"), which contains the entire server response - everything that I need.
The problem is, when I was previously using success: within the .ajax function, "this" referred to the ajax object (I think - Javascript beginner), and thence to the page element I wanted to update with the response data. I lose access to "this" in my custom callback.
What I've found is that even though I always get a response from the server, and my callback fires, JQuery reports an error - if I specify error:, then this will fire. If I add a complete:, this fires too, but success: never fires.
I thought that I could use :complete in place of my custom callback, but it appears that when the error handling code is invoked, it wipes out the server response - I can't access it in complete: (The XHR object .responseText property is "undefined" by the time processing reaches complete:).
So, my cobbled together solution to all of this is as follows. I have my custom callback, which is passed the full server response. I store this in a global variable. I specify complete: - which fires next (or later) - and then access the global variable from there, but ALSO have access to the page element I want to update via "this".
This concerns me because several AJAX requests may be made in quick succession, so my solution depends upon there being no "interleaving" of response handling - in other words, I'm making an assumption (which I don't know to be true) that when a response is received by JQuery, it will fire all of the event handlers for that response before beginning processing of the next received response. If this ISN'T so, then the data I store in my global variable may not correspond to the page element I want to use it with in success:. It seems to be working so far in testing, but it may just be that I've been lucky.
(Side note: I also use QTip2, and it's AJAX plugin - that always throws an error too, and not a silent one. But I found I could suppress this by adding error: and setting the xhr.status = 0 - I'll post a snippet below).
But this seems like such a horrible messy way of doing things. I don't understand why JQuery thinks there's been an error when the server response is received successfully. And it's very inconvenient that its error handling destroys this response which means I can't get at it in success:.
Does anyone have a neater solution? Thank you in advance - snippets to follow (by the way, these problems ONLY exist when I do all of this within my add-on. If I do the same stuff in a stand-alone page/script, it executes without errors being raised, and exactly as expected).
unsafeWindow.callback = function(data)
{
MyGlobalServerResponseVariable = data;
}
$.ajax(
{
url: 'http://nottherealurl.com/',
type: 'GET',
data: params,
async: true,
cache: false,
contentType: "text/json; charset=utf-8",
dataType: 'jsonp',
crossDomain: true,
jsonpCallback: "callback",
complete: function(xhr, textStatus)
{
var data = MyGlobalServerResponseVariable;
this.PageElementIWantToUpdate.attr("title", data.somevalue);
...
}
...
}
QTip2 error suppression:
error: function(xhr, status, error)
{
xhr.status = 0;
}
Final note, not directly related to the above - when I do "File->Open File" in Firefox and select a web page, my add-on is not executed. Is this by design?