Foliotek Development Blog

jQuery Check All Checkbox

Wednesday, August 17th, 2011

The Problem

Create a “select all” checkbox that

  1. when checked or unchecked, applies its value to all the checkboxes defined as its children
  2. when a child checkbox is checked or unchecked, the “select all” checkbox is updated accordingly. ?So, if you click the “select all”, but then uncheck one child checbox, deselect the “select all” checkbox.

The Solution



initSelectAll: function ($chkAll, $checkboxes) {

    //when chkAll is clicked, update the other checkboxes with its value
    $chkAll.click(function () {
        $checkboxes.attr("checked", $chkAll.attr("checked")); 
    });

    // when any child checkbox is checked or unchecked reset the chkAll value
    // chkAll will be checked if number of checked checkboxes = total number of checkboxes.
    $checkboxes.click(function () {
        $chkAll.attr("checked", $checkboxes.filter(":checked").length == $checkboxes.length);
    }
}

$chkAll = $("#chkAll"); // or however you select the select all checkbox
$checkboxes = $("#checkboxes :checkbox");

$(function () {
    initSelectAll($chkAll, $checkboxes);
});


Setting a threshold on jQuery ajax callbacks using prefilters

Wednesday, May 18th, 2011

Skip straight to the demo.

When developing interfaces that include ajax functionality there will come a time when you will be showing some sort of loading animation and it will only show for a split second since the ajax call finished so fast. ?This can cause the user to be disoriented since they aren’t exactly sure what popped up. ?It can be beneficial to slow down the interface so the user can see everything that is going on.

In jQuery 1.5, there is now a way to extend the $.ajax method. ?There are three different ways to extend $.ajax: prefilters, converters, and transports. ?I am going to use prefilters which the jQuery documentation describes as “generalized beforeSend callbacks to handle custom options or modify existing ones”. ?I’m not going to go into details about what a prefilter is since the?documentation does a pretty good job.

Instead of setting up timeouts and clearing them out, I am wanting to pass a custom option to the ajax method. ?Here is what I am trying to go for:


$.ajax(url, {
    ...
    successThreshold: 3000,
    ...
})

The successThreshold option is my custom option. ?The time passed into it will be the minimum amount of time it takes before the success callback gets called. ?Now that I have my custom option, I can access it and modify the other options in my prefilter.


$.ajaxPrefilter(function?(options,?originalOptions,?jqXHR)?{
    if?(originalOptions.successThreshold && $.isFunction(originalOptions.success))?{
        var?start,?stop;
        
        options.beforeSend?=?function?()?{
            start?=?new?Date().getTime();
            if?($.isFunction(originalOptions.beforeSend))
                originalOptions.beforeSend();
        };
        
        options.success?=?function?(response)?{
            var?that?=?this,?args?=?arguments;
            stop?=?new?Date().getTime();

            function?applySuccess()?{
                originalOptions.success.apply(that,?args);
            }

            var?difference?=?originalOptions.successThreshold?-?(stop?-?start);
            if?(difference?>?0)
                setTimeout(applySuccess,?difference);
            else
                applySuccess();
        };
    }
});

The first thing I do in the prefilter is check to make sure both the successThreshold and success function are set. ?I then override the beforeSend option in order to get the time before the ajax call starts. ?In order to keep the success callback from firing before the threshold, the time difference needs to be calculated. ?If the call didn’t take longer than the difference then set a timeout for the remaining time. ?Otherwise just call the success callback immediately.

I have seen other solutions to this and all of them seem to set timeouts and clear them in different functions and it would have to be repeated for every call. ?This can be defined in one place and used on any ajax call in the application.

I have added the code to my Github repository. ?This demo shows the code in action.

bindWithDelay jQuery Plugin

Friday, August 6th, 2010

Sometimes, I want to have a JavaScript event that doesn’t fire until the native event stops firing for a short timeout. I’ve needed to use that pattern in almost every project I have worked on.

For example, you want to use JavaScript to resize an iframe to 100% height when the window resizes. The resize() event can fire dozens of times, and calculating and setting the new height can slow down your page. I used to implement it like this:


var timeout;
function doResize(e) {
   clearTimeout(timeout);
   timeout = setTimeout(function() {
      // run some code
   }, 200);
}
$(function() {
   $(window).bind("resize",doResize);
});

Notice that there are extra variables that you have to deal with, and extra indentation. You could at least clean up the global variable using closures, but you get the idea.

I wrote a plugin to make this pattern easier, it is called “bindWithDelay”. The source code is online, as is a mini project page with a demo.

This is what the same code looks like with the plugin:


function doResize(e) {
      // run some code
}
$(function() {
   $(window).bindWithDelay("resize", doResize, 200);
})

Radio button within a repeater problem

Thursday, July 29th, 2010

Recently I was developing a system to create tests and test questions.? For these tests our client wanted multiple choice questions.? To implement this I decided to have a list of textboxes for the answer text, and a radio button for each textbox to select the correct answer.?? I knew that a RadioButtonList couldn’t have anything other than a radio button and text, so I went with a repeater.


<asp:Repeater ID="rptRadios" runat="server">
    <HeaderTemplate>
        <ul>
    </HeaderTemplate>
    <ItemTemplate>
        <li>
            <asp:RadioButton ID="rbRadio" runat="server" GroupName="RadioGroup" />
            &amp;nbsp;
            <asp:TextBox runat="server" ID="txtRadio"></asp:TextBox>
        </li>
    </ItemTemplate>
    <FooterTemplate>
        </ul>
    </FooterTemplate>
</asp:Repeater>

Doing it this way caused the group name of each radio button to be inconsistent, because of the repeater. After a while of researching and not finding any good solutions I decided to try changing the group name of the radio buttons using jQuery.


$("input:radio").attr('name', 'RadioGroup');

That gave me the radio button functionality that I wanted, but it prevented me from getting the selected radio button on postback. So I decided to just implement the radio button functionality manually.


var radios = $("input:radio");
radios.click(function() {
     radios.removeAttr('checked');
     $(this).prop("checked", true);
    //$(this).attr('checked', 'checked'); // jQuery < 1.6
     return true;
});

Which gave me the correct functionality and I could still get the selected radio button and textbox on postback. Probably not the most elegant solution, but I couldn?t find any other way to do it.

Also I needed to make sure at least one of the radio buttons was selected so I added a CustomValidator that called a javascript function.


function ValidateRadioButtons(sender, args) {
     args.IsValid = $("input:radio:checked").size() > 0;
}

Using jQuery and YQL to get an RSS feed from a site

Friday, February 26th, 2010

Finding an RSS feed on a site can sometimes be a hassle.? Browsers have started introducing a feature that will include an RSS icon in the address bar when the browser finds the site has an RSS feed.? I thought it would be nice to allow users to just enter in a web address and let us do the work finding the RSS feed for the site.? I looked into how browsers were accomplishing this and found that browsers look for a <link> tag in the <head> of the document with the type attribute of “application/rss+xml”.

Now that we know what to look for, how do we go about determining if the website provided has the correct <link> tag?? I decided to let YQL do the work for me.? I loaded up the YQL Query Console and began testing some queries.? On the right hand side, there are different Data Tables you can use.? I scrolled down to “data” and selected the “html” option which allows you to query the html of any site.

The example that you start out with looks similar to this:


select * from html where url="http://finance.yahoo.com/q?s=yhoo" and xpath='//div[@id="yfi_headlines"]/div[2]/ul/li/a'

From this example it is easy to see which URL is being queried and the XPath that is being used to find elements on the page.? If you aren’t familiar with? XPath, check out the W3 XPath documentation.? So now we just plug in the URL of the site we want to search and change the XPath to whatwe need to use to find the <link> elements. Now the query looks like this:


select * from html where url="http://lanitdev.wordpress.com/" and xpath='//link[@type="application/rss+xml"]'

In the query console, be sure to select the JSON radio button and then click the “Test” button.? You will see JSON output that looks like the following:


feeds({
    "query":{
    "count":"1",
    "created":"2010-02-26T09:08:43Z",
    "lang":"en-US",
    "updated":"2010-02-26T09:08:43Z",
    "uri":"http://query.yahooapis.com/v1/yql?q=select+*+from+html+where+url%3D%22http%3A%2F%2Flanitdev.wordpress.com%22+and%0A++++++xpath%3D%27%2F%2Flink%5B%40type%3D%22application%2Frss%2Bxml%22%5D%27",
    "results":{
        "link":{
            "href":"http://lanitdev.wordpress.com/feed/",
            "rel":"alternate",
            "title":"The Lanit Development Blog RSS Feed","type":"application/rss+xml"
        }
    }
}
});

We can see from the JSON that we found 1 feed and we get all the information to go along with it.

Now that we have a proper YQL query,let’s use some jQuery to create a form that retrieves these feeds for us.? I am going to create a simple form where a user inputs a url and then outputs a list of RSS feeds or a message stating that an RSS feed couldn’t be found.

The form is straightforward.? I just have a textbox and a button.? I also have an unordered list which I’ll use to display the list of RSS feeds.


<table>
    <tr>
        <td>
            <label><input type="text" id="website"></label>
        </td>
        <td>
            <input id="getrss" type="button" value="Get RSS">
        </td>
    </tr>
</table>

<ul id="rsslist">
</ul>

Next is the jQuery.? We will attach an event to the button that will hit the YQL URL and return JSON that we can parse and get the data we need.? The YQL URL we will be using is found in the YQL Query Console next to where you entered the query.? There is a box called “The REST Query” which has the query that we will use.? The only modification I made to the rest query was that I took out the URL that was in there and replaced with with the jQuery value from the textbox.


$(function(){
    $("#getrss").click(function(){
        $("#rsslist").empty();
        $.ajax({
            type: "GET",
            url: "http://query.yahooapis.com/v1/public/yql?q=select%20*%20from%20html%20where%20url%3D%22"  + $("#website").val() + "%22%20and%0A%20%20%20%20%20%20xpath%3D'%2F%2Flink%5B%40type%3D%22application%2Frss%2Bxml%22%5D'&format=json&diagnostics=false",
            dataType: "json",
            success: function(data){
                if (data.query.count == 1){
                    $("#rsslist").append("<li><a href="" + data.query.results.link.href + "">" + data.query.results.link.title + "</a></li>");
                }
                else if (data.query.count > 1){
                    for (var i = 0; i < data.query.results.link.length;="" i++)="" {="" var="" link="data.query.results.link[i];"><li><a href="" + link.href + "">" + link.title + "</a></li>");
                    }
                } else {
                    $("#rsslist").append("<li>No RSS feed found</li>");
                }
             },
             error: function(){
                 console.log("error");
             }
        });
     });
})

When the AJAX request finishes successfully we check to see if any feeds are returned and if there are, we loop through them and display them.

I created a demo page using jsbin.com so you can see this in action. View Demo

I hope this small example gives you an idea how you can use jQuery and YQL to accomplish other interesting challenges.