Firefox SDK + JQuery AJAX problems
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?
No comments:
Post a Comment