Mutually exclusive checkbox in a gridview

Hi,
I have a gridview with 4 rows, and a checkbox on the first column.
When a user click on the checkbox in any one row, the checkboxes from the other rows should become uncheck.
Below is the Gridview,
The javascript code to uncheck the checkboxes from the other rows
The javascript onclick event generated on the RowDataBound event of the grdview.

The code run successfully on the RowDataBound, and populate the onclick even. However when I click on a checkbox, the other checkboxes are not unticked.

I am just starting to work with JavaScript, could you please help me with this one.

Thank you




Gridview:
<asp:Panel ID="pnlParameter" runat="server" Visible="false">
   <asp:Label ID="lblFQID" runat="server"/>
</asp:Panel>

<asp:GridView ID="GV" runat="server" AutoGenerateColumns="false" OnRowDataBound="GV_RowDataBound">
    <Columns>
        <asp:TemplateField HeaderText="Correct answer">
        <ItemTemplate>
             <asp:CheckBox ID="CheckBox1" runat="server" />
        </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField Visible="true" HeaderText="Description">
        <ItemTemplate>
            <asp:TextBox ID="txtQuestionDesc" Text='<%# Eval("QuestionDesc") %>' runat="Server" />
        </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

Open in new window


JavaScript function:
<script type="text/javascript" language="javascript">
    function uncheckOthers(id) {
        var elm = document.getElementsByTagName('input');
        for (var i = 0; i < elm.length; i++) {
            if (elm.item(i).id.substring(id.id.lastIndexOf('_')) == id.id.substring(id.id.lastIndexOf('_'))) {
                if (elm.item(i).type == "checkbox" && elm.item(i) != id)
                    elm.item(i).checked = false;
            }
        }
    }
   </script>

Open in new window


C# event:
        protected void GV_RowDataBound(object source, GridViewRowEventArgs e)
        {
            if (e.Row is GridViewRow & e.Row.RowType == DataControlRowType.DataRow)
            {
                string strScript = "uncheckOthers(" + ((CheckBox)e.Row.Cells[0].FindControl("CheckBox1")).ClientID + ");";
                ((CheckBox)e.Row.Cells[0].FindControl("CheckBox1")).Attributes.Add("onclick", strScript);
            }
        }

Open in new window

AnneSKSAsked:
Who is Participating?
 
Julian HansenCommented:
That is because the checkboxes are being created dynamically

To solve this we use the .on() and bind it to a parent element

Try this. Replace the jQuery with this. Here I have replaced the mousedown() event with an .on() which is attached to body and I have specified the span.exclusive selector as being the target. So even if check boxes are added dynamically (like after a postback) the event should fire on the new elements.

 $(function () {
            $('body').on('mousedown', 'span.exclusive', function () {
                var linked = $(this).data('linked');
                $('span[data-linked="' + linked + '"] input:checkbox').prop('checked', false);
            });
        });

Open in new window

0
 
Julian HansenCommented:
Why not use a radio button? A radio button is exactly that - a mutually exclusive check box?

Failing that you can do this quite easily with jQuery
HTML
    <input type="checkbox" class="exclusive" data-linked="group1" value="1"/><br/>
    <input type="checkbox" class="exclusive" data-linked="group1" value="2"/><br/>
    <input type="checkbox" class="exclusive" data-linked="group1" value="3"/><br/>
    <input type="checkbox" class="exclusive" data-linked="group1" value="4"/>

Open in new window

jQuery
<script src="http://code.jquery.com/jquery.js"></script>
<script>
$(function() {
  $('.exclusive').mousedown(function() {
    var linked = $(this).data('linked');
    $(':checkbox[data-linked="' + linked + '"]').prop('checked', false);
  });
});
</script>

Open in new window

Working sample here
0
 
AnneSKSAuthor Commented:
Hi Julian,
Thank you for your comment.
I'm ok with radio button, however
there is only 1 radio button/checkbox per row. And you can only select one in the gridview.
I've got the impression that your 4 radio buttons are on the same row.
0
Ultimate Tool Kit for Technology Solution Provider

Broken down into practical pointers and step-by-step instructions, the IT Service Excellence Tool Kit delivers expert advice for technology solution providers. Get your free copy now.

 
Julian HansenCommented:
If you look at the sample I posted (and read the Breakdown) you will see in the third group of buttons I have mixed them.

The whole purpose of the design is that you can put the checkbox anywhere on your page and link them to any other checkbox simply by
a) Adding the "exclusive" class to the checkbox
b) Adding the data-link custom attribute to the checkbox and setting it to the group name you want the checkbox to be part of
c) Including the jQuery code I posted in my post above and the sample

Here is a link to the sample again - look at the Group 3 (Mixed) group. That is made up of items from group1 and group2 - when you click the checkboxes in this group it changes the state of the checked buttons in Group 1 and Group 2
0
 
AnneSKSAuthor Commented:
The problem in my post is not the grouping of checkbox and the exclusivity.
The problem is how to set up the exclusivity or the group in a the gridview, when the checkbox are in different rows, therefore the group cannot be hardcoded.

If you look at my code, in the  GV_RowDataBound event of the gridview, I am attempting to create a group. However it is not working.
0
 
Julian HansenCommented:
when the checkbox are in different rows, therefore the group cannot be hardcoded.
I don't see the problem - the solution I provided allows for this?
You can have this

<table>
  <tr>
    <td><input type="checkbox" class="exclusive" data-link="group1" value="1"/></td>
  </tr>
  <tr>
    <td><input type="checkbox" class="exclusive" data-link="group1" value="2"/></td>
  </tr>
  <tr>
    <td><input type="checkbox" class="exclusive" data-link="group1" value="3"/></td>
  </tr>
  <tr>
    <td><input type="checkbox" class="exclusive" data-link="group1" value="4"/></td>
  </tr>
</table>

Open in new window

It will work - all you need to do is give the checkboxes a class of "exclusive" and for all those that are in the same group a custom attribute data-link="group1"
0
 
Julian HansenCommented:
when the checkbox are in different rows, therefore the group cannot be hardcoded.
Can you explain why you think they cannot be grouped?
0
 
AnneSKSAuthor Commented:
Julian,
I am talking about a gridview, not a table. They don't work the same. As I said, hard coding in html the group will not work. Believe me.
The group has to be generated in the RowDatabound event of the gridview, please check the code below. But in the work that I have done, it does not work.

In the event, I am 'grouping' the  checkbox using the following code. It should theoretically call a javascript function 'UncheckOthers' when one of the 'onclick' event of any of these check box is fired.

 string strScript = "uncheckOthers(" + ((CheckBox)e.Row.Cells[0].FindControl("CheckBox1")).ClientID + ");";
                ((CheckBox)e.Row.Cells[0].FindControl("CheckBox1")).Attributes.Add("onclick", strScript);

However, the RowDataBound event is fired and theoretically the script is added to the onclick event, when I run the form, the checkbox are not unticked when I tick one.

So I don't know, if there is a problem in either the strscript or in adding the script to the onclick event, or maybe the problem is in the javascript function. As I said previously I am not very good at JavaScript, so I could have missed something.        

Also, I am using an <asp:Checkbox/>, as I need to save the gridview result and which box has been ticked/unticked. There is a lot more in this gridview, but I have streamlined it to just show the current requirements.    

Thank you for your help.


<asp:GridView ID="GV" runat="server" AutoGenerateColumns="false" OnRowDataBound="GV_RowDataBound">
    <Columns>
        <asp:TemplateField HeaderText="Correct answer">
        <ItemTemplate>
             <asp:CheckBox ID="CheckBox1" runat="server" />
        </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField Visible="true" HeaderText="Description">
        <ItemTemplate>
            <asp:TextBox ID="txtQuestionDesc" Text='<%# Eval("QuestionDesc") %>' runat="Server" />
        </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

Open in new window


protected void GV_RowDataBound(object source, GridViewRowEventArgs e)
        {
            if (e.Row is GridViewRow & e.Row.RowType == DataControlRowType.DataRow)
            {
                string strScript = "uncheckOthers(" + ((CheckBox)e.Row.Cells[0].FindControl("CheckBox1")).ClientID + ");";
                ((CheckBox)e.Row.Cells[0].FindControl("CheckBox1")).Attributes.Add("onclick", strScript);
            }
        }

Open in new window


<script type="text/javascript" language="javascript">
    function uncheckOthers(id) {
        var elm = document.getElementsByTagName('input');
        for (var i = 0; i < elm.length; i++) {
            if (elm.item(i).id.substring(id.id.lastIndexOf('_')) == id.id.substring(id.id.lastIndexOf('_'))) {
                if (elm.item(i).type == "checkbox" && elm.item(i) != id)
                    elm.item(i).checked = false;
            }
        }
    }
   </script>

Open in new window

0
 
Julian HansenCommented:
The table was to demonstrate a concept

1. Can you add a class to your checkbox items
2. Can you add a custom attribute

That is all you need. You appear to be trying to handle the unchecking in the Event handler which is unnecessary as you can handle it in the client with a few lines of JavaScript.

Remember your ASP code generates HTML - it does not matter what HTML it generates as long as you can add a class to your checkbox controls and a custom data attribute. That is all you need to do and the JavaScript code I provided will work.
0
 
Julian HansenCommented:
Ok I went ahead and built an ASPX version of this. One little fact I was unaware of was that ASP wraps checkboxes inside a <span> so you need to modify the jQuery a bit to take that into account.

Here is how I defined my checkbox
        <asp:TemplateField HeaderText="Correct answer">
            <ItemTemplate>
                 <asp:CheckBox ID="CheckBox1" runat="server" CssClass="exclusive" data-linked="group1"/>
            </ItemTemplate>
        </asp:TemplateField>

Open in new window


Here is the updated jQuery code
<script>
    $(function () {
        $('span.exclusive').mousedown(function () {
            var linked = $(this).data('linked');
            $('span[data-linked="' + linked + '"] input:checkbox').prop('checked', false);
        });

    });
</script>

Open in new window

Works as expected
0
 
AnneSKSAuthor Commented:
Hi Julian,
You are fantastic. I am in meeting all morning, but will implement it early afternoon (Australian time), and let you know how I am going.

So if I understand, I have to create a user control for my checkbox and create a data-linked property and add the CSSClass . This usercontrol can go into the gridview.

Now if I only have one set of checkbox, and they are all in the same group, do I need the data-linked property, or the cssclass can be enough? Which mean in this case that I don't need to create the usercontrol.

Then in the RowDataBound event of the gridview I have to add your function to the onclick event of this usercontrol.

And then of course add the function into my page.

Thank you

Anne
0
 
AnneSKSAuthor Commented:
Hi Julian,
I cannot make it work. There is too many parameters that I don't know to solve the issue.
Would you mind having a look at my code, and see if it works for you, and if not what does not work.

Theoretically it should be working, and it could be a simple mistake.

Thanks

Anne
0
 
Julian HansenCommented:
I can - if you post what you have done.

Here is my code
Code behind I use to create the data source for the grid
using System;
using System.Data;

public partial class _Default : System.Web.UI.Page 
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //Multi-Dimensional Array
        string[,] arrMultiD = { 
                            { "John", "21", "Berlin", "Germany" }, 
                            { "Smith", "33" ,"London", "UK"}, 
                            { "Ryder", "15" ,"Sydney", "Australia"}, 
                            { "Jake", "18", "Tokyo", "Japan"}, 
                            { "Tom","34" , "Mumbai", "India"}
                         };
        DataTable dt = new DataTable();
        dt.Columns.Add("Name", Type.GetType("System.String"));
        dt.Columns.Add("Age", Type.GetType("System.String"));
        dt.Columns.Add("City", Type.GetType("System.String"));
        dt.Columns.Add("Country", Type.GetType("System.String"));     
        for (int i = 0; i < 5; i++)
        {
            dt.Rows.Add();
            dt.Rows[dt.Rows.Count - 1]["Name"] = arrMultiD[i, 0];
            dt.Rows[dt.Rows.Count - 1]["Age"] = arrMultiD[i, 1];
            dt.Rows[dt.Rows.Count - 1]["City"] = arrMultiD[i, 2];
            dt.Rows[dt.Rows.Count - 1]["Country"] = arrMultiD[i, 3];   
        }
        GridMultiD.DataSource = dt;
        GridMultiD.DataBind();  
    }
}

Open in new window

Here is my aspx file
<%@ Page Language="C#" AutoEventWireup="true" Inherits="_Default" Codebehind="CSharp.aspx.cs" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
 
<head runat="server">
    <title>Binding Array to GridView Example</title>
    <script src="http://code.jquery.com/jquery.js"></script>
    <script>
        $(function () {
            $('span.exclusive').mousedown(function () {
                var linked = $(this).data('linked');
                $('span[data-linked="' + linked + '"] input:checkbox').prop('checked', false);
            });

        });
    </script>
</head>
<body>
    <form id="form1" runat="server">
    <div>
    <br />
    <asp:GridView ID="GridMultiD" runat="server" 
        AutoGenerateColumns = "false" Font-Names = "Arial" 
        Font-Size = "11pt" AlternatingRowStyle-BackColor = "#C2D69B"  
        HeaderStyle-BackColor = "green" AllowPaging ="true"   
        PageSize = "10" Caption = "Multi-Dimensional Array" >
       <Columns>
        <asp:TemplateField HeaderText="Correct answer">
            <ItemTemplate>
                 <asp:CheckBox ID="CheckBox1" runat="server" CssClass="exclusive" data-linked="group1"/>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:BoundField ItemStyle-Width = "150px" DataField = "Name" HeaderText = "Name" />
        <asp:BoundField ItemStyle-Width = "150px" DataField = "Age" HeaderText = "Age" />
        <asp:BoundField ItemStyle-Width = "150px" DataField = "City" HeaderText = "City" />
        <asp:BoundField ItemStyle-Width = "150px" DataField = "Country" HeaderText = "Country" />
       </Columns> 
    </asp:GridView>    
    </div>
    </form>
</body>
</html>

Open in new window

I have a working sample here
0
 
AnneSKSAuthor Commented:
Hi Julian,
I am almost there, I have managed to make it work if the checkbox and the functions are in a page. However it does not work if it is in a user control.
Any suggestions?
Thanks again for your help.

Anne
0
 
AnneSKSAuthor Commented:
I found the problem, the problem is with postback in an update panel. After the postback, the checkboxes are not mutually exclusive anymore.

Any idea how to change/prevent it

Thank you

Anne
0
 
AnneSKSAuthor Commented:
Hi Julian,
Thank you so much for your help, it was fantastic.

I am just starting to learn JavaScript and JQuery, I am using Lynda.com to learn.
Is there any website that you would recommend, especially one with samples, or that could explain when they are best to use.

Once again thank you so much.

Anne
0
 
Julian HansenCommented:
You are most welcome.

To tell the truth - I learned most of what I know hanging around EE looking at the questions people ask, trying to answer them and looking at the solutions.

There are a couple of good books out there recommended by various experts - I will try and dig up the URLS.

JavaScript is very mature the Net is littered with thousands of resources so Google could also be your friend here.
1
 
Julian HansenCommented:
Here are the resources I mentioned

https://www.manning.com/books/secrets-of-the-javascript-ninja
http://shop.oreilly.com/product/9780596802806.do

There is also this site which has some good resources

http://ejohn.org/apps/learn/
0
Question has a verified solution.

Are you are experiencing a similar issue? Get a personalized answer when you ask a related question.

Have a better answer? Share it in a comment.

All Courses

From novice to tech pro — start learning today.