iOS Safari Browser Has A Massive Caching Issue!

Safari iOS6It wasn’t until today I found that the Safari browser used on iPad and iPhone caches page functionality to such an extent that it stops the intended functionality. So much so, it affects the user experience. I think Apple has gone a step too far in making their browser uber efficient to minimise page loading times.

We can accept browsers will cache style-sheets and client side scripts. But I never expected Safari to go as far as caching responses from web services. This is a big issue. So something as simple as the following will have issues in Safari:

// JavaScript function calling web service
function GetCustomerName(id)
{
    var name = "";

    $.ajax({
        type: "POST",
        url: "/Internal/ShopService.asmx/GetCustomerName",
        data: "{ 'id' : '" + id + "' }",
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        cache: false,
        success: function (result) {
            var data = result.d;
            name = data;
        },
        error: function () {
        },
        complete: function () {
        }
    });
    
    return name;
}
//ASP.NET Web Service method
[WebMethod]
public string GetCustomerName(int id)
{
   return CustomerHelper.GetFullName(id);
}

In the past to ensure my jQuery AJAX requests were not cached, the “cache: false” option within the AJAX call normally sufficed. Not if you’re making POST web service requests. It’s only until recently I found using “cache:false” option will not have an affect on POST requests, as stated on jQuery API:

Pages fetched with POST are never cached, so the cache and ifModified options in jQuery.ajaxSetup() have no effect on these requests.

In addition to trying to fix the problem by using the jQuery AJAX cache option, I implemented practical techniques covered by the tutorial: How to stop caching with jQuery and JavaScript.

Luckily, I found an informative StackOverflow post by someone who experienced the exact same issue a few days ago. It looks like the exact same caching bug is still prevalent in Apple’s newest operating system, iOS6*. Well you didn’t expect Apple to fix important problems like these now would you (referring to Map’s fiasco!). The StackOverflow poster found a suitable workaround by passing a timestamp to the web service method being called, as so (modifying code above):

// JavaScript function calling web service with time stamp addition
function GetCustomerName(id)
{
    var timestamp = new Date();

    var name = "";

    $.ajax({
        type: "POST",
        url: "/Internal/ShopService.asmx/GetCustomerName",
        data: "{ 'id' : '" + id + "', 'timestamp' : '" + timestamp.getTime() + "' }", //Timestamp parameter added.
        contentType: "application/json; charset=utf-8",
        dataType: "json",
        cache: false,
        success: function (result) {
            var data = result.d;
            name = data;
        },
        error: function () {
        },
        complete: function () {
        }
    });
    
    return name;
}
//ASP.NET Web Service method with time stamp parameter
[WebMethod]
public string GetCustomerName(int id, string timestamp)
{
    string iOSTime = timestamp;
    return CustomerHelper.GetFullName(id);
}

The timestamp parameter doesn’t need to do anything once passed to web service. This will ensure every call to the web service will never be cached.

*UPDATE: After further testing it looks like only iOS6 contains the AJAX caching bug.

Solving Flash Issues in Isotope jQuery Plugin

I’m using a jQuery plugin called “Isotope” to nicely output a mixture of news articles and advertising banners to a page.

I came across a small issue when using advertising banner’s in Flash format. For some reason, Flash content displayed randomly and mouse-clicks were not registered. This issue only seemed to only occur in Firefox. I couldn’t replicate this issue on other browsers.

Thankfully, only one additional line of code  needed to be added when when initially setting the Isotope plugin options:

$('#wall').isotope({
    itemSelector: '.box',
    animationEngine: 'css,
    layoutMode: 'masonry',
    transformsEnabled: false //Disable transformations
});

The following example helped me further in resolving my issue: http://isotope.metafizzy.co/tests/flash.html

Get CheckBoxList Values Using jQuery

To be able to retrieve values from a ASP.NET CheckBoxList control or a group of HTML checkboxes, use the following jQuery:

$(document).ready(function () {
    var checkboxValues = [];

    $('#<%=MyCheckBoxList.ClientID %> input[type=checkbox]').click(function () {
        $('input[type=checkbox]:checked').each(function () {
            checkboxValues.push(this.value);
        });        
    });
    
    var values = checkboxValues.toString(); //Output Format: 1,2,3
});

If you do use this code snippet on a CheckBoxList, take a look that this article on how to create a custom CheckBoxList control with a value attribute.

Calling a ASP.NET Method Using jQuery

Over the last few months I have had the ability to mess around with a bit of jQuery. Even though I don’t have the complete understanding on how it works, I can see the benefits of writing my code in jQuery compared to bashing out lots of lines of JavaScript to do the same thing.

One the cool features I have used is calling one of my .NET methods using the “$.ajax” jQuery command. In my example (below), I have created two aspx pages. The code-behind of my first page  (jQueryMethodTest.aspx) will only contain a public static method called “WhatIsYourName”, which returns a string value.

[WebMethod]
public static string WhatIsYourName(string name)
{
    if (!String.IsNullOrEmpty(name))
    {
        return String.Concat("Hello ", name, "!");
    }
    else
    {
        return String.Empty;
    }
}

Remember, the jQueryMethodTest.aspx page only needs to contain our method nothing else! Additional methods can be added. Just don’t add any web controls.

The second page (jQueryAjax.aspx), will contain our jQuery code and some HTML to output our result from calling the “WhatIsYourName” method.

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <script type="text/javascript" language="javascript" src="javascript/jquery.js"></script>
</head>
<script type="text/javascript">
    $(document).ready(function() {
        $("#btnSubmitName").click(function(event) {
            $.ajax({
                type: "POST",
                url: "jQueryMethodTest.aspx/WhatIsYourName",
                data: "{'name': '" + $('#name').val() + "'}",
                contentType: "application/json; charset=utf-8",
                dataType: "json",
                success: function(message) {
                    ShowPopup(message);
                },
                error: NameFailed
            });
        });
    });

    function ShowPopup(result) {
        if (result.d != "") {
            $("#Message").html(result.d);
        }
        else {
            $("#Message").html("I didn't get your name.");
        }
    }

    function NameFailed(result) {
        $("#Message").html(result.status + ' ' + result.statusText);
    }  
  </script>  

<body>
    <form id="form1" runat="server">
    <div>
        <input id="name" name="name" type="text" />
        <br />
        <input id="btnSubmitName" name="btnSubmitName" type="button" value="Submit" />
        <br /><br />
        <span id="Message" style="color:Red;"></span>
    </div>
    </form>
</body>
</html>

If all goes well, you should get the following result:

Calling ASP Method Using jQuery

The “$.ajax” jQuery command requires the following parameters in order to work:

  • url – links to where our .NET method is placed.
  • data – retrieves the value from some control in our page to pass to our method. Remember, the name of the parameter must be named the same as the parameter from our .NET method.
  • dataType – the response type.
  • contentType – the request content type.
  • success – the JavaScript function that gets fired on postback.
  • error – the Javascript function that gets fired if there is a failure. This is an optional parameter.

 

I guess jQuery’s motto really is true: “write less, do more”.