More Cordova/jQuery mobile pain: ajax and events

von

When updating the mobile client of Time & Bill I run into jQuery mobile trouble again. This time lost nearly 12 hours for problems nobody does need. And yes, Open Source or not - I have considered Appcelerator meanwhile. I already downloaded the SDK, but for now I try to fix my mobile client.

What happened? I added a new feature and realized my login does not work all the time. You can login one hundred times, but then it will fail silently: some AJAX request still do not get through. Wow, not again.

My environment is Apache Cordova 1.5 (formerly known as Phonegap) and jQuery mobile 1.0.1 on Android. jQuery mobile one is not recommended by me. It is not only slow, it is a time eater. In my opinion it only gets so much attention because of the name. MicroJS knows some good alternatives, but for now I am stuck.

My first advise for users of the same constellation: do not use jQuery mobiles “mobileinit” method. It is not always called in some (unknown) cases. Instead, you can use that event, which is triggered from Cordova:

function onDeviceReady() { ... }

document.addEventListener(
   "deviceready", onDeviceReady, false);

For now I can say it works as expected. Apache Cordova knows a few other events, like “menubutton”, “backbutton”, “pause” and “resume” (thanks Cordova guys).

While “Pause” is send when an application wents in background, “Resume” happens when it is activated again. Be careful: “Resume” happens each time I switch to another page with jQuery mobile. As a workaround I let the “Pause” event set a flag, which I will check when I “Resume”. This is not nice, but the only way I know to get over that behavior. I am not sure if this is a Cordova problem or a jQuery mobile problem, but my guess is it has something to do with the second one.

Still I had problems with my AJAX request. I checked if they are cached - they are not. Sometimes the requests seem to start, but never finish. I have found out, this might (!) be true if you send a response back which does not contain the crosssite headers. This was the case in a few occasions in my server, so I had to add a Filter to my web.xml which does set all the needed headers for specific URLs:

public class CrossdomainFilter implements Filter {
  @Override
  public void init(FilterConfig filterConfig) 
    throws ServletException {
  }

  @Override
  public void doFilter(ServletRequest request, 
                       ServletResponse res, 
                       FilterChain chain) 
      throws IOException, ServletException {
      HttpServletResponse r = (HttpServletResponse)res;
      r.setHeader("Cache-Control", 
         "no-cache, no-store, must-revalidate");
      r.setHeader("Pragma", "no-cache");
      r.setDateHeader("Expires", 0);
      r.setHeader("Access-Control-Allow-Origin", "*");
      r.setHeader("Access-Control-Allow-Methods", 
         "POST,GET,OPTIONS");
      r.setHeader("Access-Control-Allow-Credentials", 
         "true");
      chain.doFilter(request, response);
    }

    @Override
    public void destroy() {
    }
}

If you want to copy this snippet, please be aware that I disabled caching with a few more HTTP headers. You can remove them, if you wish, the necessary headers are Access-Control-Allow-*

Still this didn’t help. I have then decided to stop using the jQuery 1.6.1 (necessary for jQuery mobile 1.0.1) ajax functionality and move to PromiseJS instead. PromiseJS is a great and small utility for Futures/Promises in JavaScript. It can also do AJAX.

For my mobile app, I had to disable the following line in Promise:

// xhr.setRequestHeader('X-Requested-With', 'XMLHttpRequest');

For some reasons requests with this header are not accepted. Need to figure that out later.

Unfortunately the developer of PromiseJS seem to forgot that “delete” is a keyword in JavaScript. So I had to delete this line too:

delete: _ajaxer('DELETE')

If you need to send a Delete-Request, you simply can rename it to something else. Besides that, promise does everything I want - and even quicker (not measured, it’s a feeling). And with lesser code - look at what I had to write with jQuery:

$.ajax({
   url: url,
   context: document.body,
   cache : false,
   data: data,
   error:   function(xhr, status, error) { ...  },
   success: function ( data, text, jqXhr ) { ... }
});

Now look at PromiseJS:

promise.post(url, data).then(function(error, data) {});

Decide yourself - but I will not use jQuery just for jQuerys sake. PromiseJS should document which browsers are supported and which are not, but then it is a good alternative for the bloated jQuery call (which is surely mighty, be who needs that all the time?).

Anyway, something is different in my App with PromiseJS now - I can rely on my AJAX requests, so it seems. Thanks Pierre, I will use your great code a lot. You can find more information on his website.

Enough for now - it’s time to clean up my source code and do some more testings. Still jQuery mobile causes me some headaches on other places. It’s my luck that Apache Cordova has improved a lot and meanwhile I get pretty good hints from the adb logcat.

Tags: #Android #Apache Cordova #JavaScript #jQuery #jQuery mobile #Open Source #phonegap

Newsletter

ABMELDEN