How to get checkbox values form a repeater (looping only finds the first)

A

Alan Silver

Hello,

I have a repeater that has code like this...

<ItemTemplate>
<asp:CheckBox ID="chkDelete" Text="" RunAt="server"/>
.... other stuff goes here
</ItemTemplate>

There is a button below the repeater. When clicked, it is supposed to
loop through the repeater items, building a list of IDs where the
checkbox was checked. This is done with code like this...

for (int i=0; i<rptProducts.Items.Count; i++) {
if (((CheckBox)rptProducts.Items.FindControl("chkDelete")).Checked)
{
// add to list
}
}

The problem is that this only ever finds the *first* checkbox that was
checked. Any subsequent ones show up as unchecked.

Any ideas? I'm completely lost. I've searched Google, but not found
anything. TIA for any help.
 
S

sloan

This isn't exact, but might help.


It assumes you have a CheckBoxList1 on your form. and the formname is
'Form1'.





<script language='javascript'>
<!--
function validate_CheckBoxList1(source) {
var objForm = document.Form1;
var errorCount = 0; //true
var objCheckBoxList = document.getElementById('CheckBoxList1');
if(objCheckBoxList == null) {
alert ('There was an issue checking the *CheckBoxList1* check box list');
return errorCount;
}
var atLeastOneIndividualItemChecked = false;
var i = 0;
var currentListItem = document.getElementById(objCheckBoxList.id + '_' + i);
while (currentListItem != null)
{
//alert (currentListItem.name);
//this loop uses the naming scheme of controlName_1, controlName_2
//to check items inside the CheckBoxList
//using the != null check should keep it from getting locked up
if (currentListItem.checked == true) {
atLeastOneIndividualItemChecked = true;
}
//increment i AND get the next control
i += 1 ;
currentListItem = document.getElementById(objCheckBoxList.id + '_' + i);
}
if (atLeastOneIndividualItemChecked == false) {
source.errormessage += varMultipleErrorSeperator + 'Select a CheckBox
Item';
errorCount+=1;
}
return errorCount;
}

// -->
</script>


If it helps, then please post a reply that it did....for the ~next guy.
 
S

sloan

Crappo.

Sorry! I thought you wanted javascript, not C# (code behind)

.............















Here is some javascript.

The key is knowing how a repeater or datagrid name the checkboxes:


Put a custom validator on your form...like this:
<asp:CustomValidator id="CustomValidator1" runat="server"
ErrorMessage="CustomValidator" Display="None"

ClientValidationFunction="CheckADataBoundControlForACheckedCheckBox"></asp:C
ustomValidator>

(thats' just to get the call to the function below to work)





<script language='javascript'>
<!--
function CheckADataBoundControlForACheckedCheckBox(source, args) {

//Customize these values.
var dataBoundControlName = 'MyRepeater'; //This is the name of the DataGrid
or Repeater
var checkBoxNameInDataBoundControl = 'chkDelete';
var objForm = document.Form1; //this is important to set correctly
//End Customize Values


var errorCount = 0; //true

var derivedName = dataBoundControlName + '__ctl1_' +
checkBoxNameInDataBoundControl;
var objCheckBoxList = document.getElementById(derivedName);
if(objCheckBoxList == null) {
alert ('There was an issue checking the
*'+checkBoxNameInDataBoundControl+'* check box in the
*'+dataBoundControlName+'* control');
return errorCount;
}


var atLeastOneIndividualItemChecked = false;
var i = 1; // Notice the 1, its important to get the start number correct



derivedName = dataBoundControlName + '__ctl' + i + '_'+
checkBoxNameInDataBoundControl;
alert(derivedName);
var currentListItem = document.getElementById(derivedName);

if(null==currentListItem)
{
alert ('It was null'); // something is wrong. Probably one of the
'Customize Values'
}

while (currentListItem != null)
{

//alert (currentListItem.name);

//to check items inside the DataGrid/Repeater
//using the != null check should keep it from getting locked up
if (currentListItem.checked == true) {
alert(currentListItem.name + ' is Checked!!');
atLeastOneIndividualItemChecked = true;
}
//increment i AND get the next control
i += 1 ;
derivedName = dataBoundControlName + '__ctl' + i + '_'+
checkBoxNameInDataBoundControl;
currentListItem = document.getElementById(derivedName);
}




if (atLeastOneIndividualItemChecked == false) {
//source.errormessage += varMultipleErrorSeperator + 'Select a CheckBox
Item';
source.errormessage = 'No checkboxes in the *'+dataBoundControlName+'*
were selected';
errorCount+=1;
}


if (errorCount > 0) {
args.IsValid = false;
}
else {
args.IsValid = true;
}


}

// -->
</script>









Alan Silver said:
Hello,

I have a repeater that has code like this...

<ItemTemplate>
<asp:CheckBox ID="chkDelete" Text="" RunAt="server"/>
... other stuff goes here
</ItemTemplate>

There is a button below the repeater. When clicked, it is supposed to
loop through the repeater items, building a list of IDs where the
checkbox was checked. This is done with code like this...

for (int i=0; i<rptProducts.Items.Count; i++) {
if (((CheckBox)rptProducts.Items.FindControl("chkDelete")).Checked)
{
// add to list
}
}

The problem is that this only ever finds the *first* checkbox that was
checked. Any subsequent ones show up as unchecked.

Any ideas? I'm completely lost. I've searched Google, but not found
anything. TIA for any help.
 
A

Alan Silver

Sorry! I thought you wanted javascript, not C# (code behind)

<g>

I was wondering!! Any ideas on the actual problem?
 
A

Alan Silver

Does the repeater control have its EnableViewState property set to

It doesn't have it set at all, which usually means that it's set to true
(the default). I tried setting it explicitly, but it didn't make any
difference.

Thanks for the reply, any more ideas?
 
G

Guest

I' ve tried the following demo
[WebForm1.aspx]
<asp:Repeater id="Repeater1" runat="server" DataSource="<%# emoticons1 %>">
<ItemTemplate>
<asp:CheckBox ID="chkDeleted" Runat="server" Text="Delete" ></asp:CheckBox>
</ItemTemplate>
</asp:Repeater>
<asp:Button id="Button1" runat="server" Text="Button"></asp:Button>

[WebForm1.aspx.cs]
private void Page_Load(object sender, System.EventArgs e)
{
if (!Page.IsPostBack)
{
sqlDataAdapter2.Fill(emoticons1);
Repeater1.DataBind();
}
}
private void Button1_Click(object sender, System.EventArgs e)
{
for(int i = 0; i < Repeater1.Items.Count; i++)
{
if ( ((CheckBox)Repeater1.Items.FindControl("chkDeleted")).Checked)
{
System.Diagnostics.Debug.WriteLine("Checked");
}
else
{
System.Diagnostics.Debug.WriteLine("Unchecked");
}
}
}
and it works fine...
Can you post more code? e.g the whole repeater control and not just the
ItemTemplate part?
 
A

Alan Silver

Konstantinos Pantos said:
Can you post more code? e.g the whole repeater control and not just the
ItemTemplate part?

Sure, but I should point out that when I copied the code into another
file to create a full page that showed the problem, it worked fine!!
This sounds like there's some weird problem with the whole page, not
just this code. I'm not sure why though.

Anyway, here's the repeater itself...

<asp:Repeater ID="rptProducts" RunAt="Server" OnItemDataBound="rptProducts_OnItemDataBound">

<HeaderTemplate><table border="0" cellpadding="2" cellspacing="0" width="100%"></HeaderTemplate>

<ItemTemplate><tr><td align="left" valign="top" class="altTableCell"><small><asp:CheckBox ID="chkDelete" Text="" RunAt="server"/>&nbsp;<asp:Imag
e ID="imgStatus" runat="server" Width="10" Height="10" />&nbsp;<asp:HyperLink ID="hlkProduct" NavigateUrl='<%# "product.aspx?productid=" +
DataBinder.Eval(Container.DataItem, "productid") %>' Text='<%#DataBinder.Eval(Container.DataItem, "PName")%>' RunAt="server" /></small></td></t
r></ItemTemplate>

<AlternatingItemTemplate><tr><td align="left" valign="top" class="tableCell"><small><asp:CheckBox ID="chkDelete" Text="" RunAt="server"/>&nbsp;<a
sp:Image ID="imgStatus" runat="server" Width="10" Height="10" />&nbsp;<asp:HyperLink ID="hlkProduct" NavigateUrl='<%# "product.aspx?productid="
+ DataBinder.Eval(Container.DataItem, "productid") %>' Text='<%#DataBinder.Eval(Container.DataItem, "PName")%>' RunAt="server" /></small></td>
</tr></AlternatingItemTemplate>

<FooterTemplate></table><small>Products marked <img src="images/product-blank.gif" alt="" /> are visible and not on special offer.<br />Products
marked <img src="images/product-special-offer.gif" alt="" /> have at least one price on special offer.<br />Products marked <img src="images/product-
not-visible.gif" alt="" /> are not visible on the web site.</small><br /></FooterTemplate>

</asp:Repeater>


The code-behind contains the following code for the OnItemDataBound
event for the repeater. Note that all this does is set the image to be
shown, depending on the status of the product. I'm certain this bit is
irrelevant to the problem...

protected void rptProducts_OnItemDataBound(object source, RepeaterItemEventArgs e) {
if (e.Item.ItemType == ListItemType.Item || e.Item.ItemType == ListItemType.AlternatingItem) {
// set the image depending on the product's status
Image imgStatus = (Image)e.Item.FindControl("imgStatus");
if (DataBinder.Eval(e.Item.DataItem, "Show_product").ToString() == "n") {
imgStatus.ImageUrl = "/images/product-not-visible.gif";
imgStatus.AlternateText = "Product is not visible";
} else if (Convert.ToInt32(DataBinder.Eval(e.Item.DataItem, "n")) > 0) {
imgStatus.ImageUrl = "/images/product-special-offer.gif";
imgStatus.AlternateText = "Product is visible and on special offer";
} else {
imgStatus.ImageUrl = "/images/product-blank.gif";
imgStatus.AlternateText = "Product is visible and not on special offer";
}
}
}

....and the following code for the button that is supposed to collect the
names of the products to delete...

public void btnDeleteProducts_Click(object o, EventArgs e) {
for (int i=0; i<rptProducts.Items.Count; i++) {
//litMsg.Text += "<br>(" + i.ToString() + ") Checking... (" + (((CheckBox)rptProducts.Items.FindControl("chkDelete")).Checked).ToString() + ") ";
if (((CheckBox)rptProducts.Items.FindControl("chkDelete")).Checked) {
//litMsg.Text += " and deleting... ";
// get the URL of the target page
string strNavUrl = ((HyperLink)rptProducts.Items.FindControl("hlkProduct")).NavigateUrl;
// extract the product ID
int productID = Convert.ToInt32(strNavUrl.Substring(strNavUrl.IndexOf("=")+1));
// get the name of the product
string strNavText = ((HyperLink)rptProducts.Items.FindControl("hlkProduct")).Text;
litMsg.Text += "Deleted " + strNavText + "<br>";
BindRepeater(Convert.ToInt32(litCatId.Text), litCatName.Text);
}
}
}

Note that this code just lists the names (pulled from the Hyperlink's
Text property), it doesn't delete them from the database yet. litMsg is
a Literal control on the page, used for me to see what's going on.

If you can see what's wrong here I would be very grateful. Thanks.
 
A

Alan Silver

This sounds like there's some weird problem with the whole page, not
just this code. I'm not sure why though.

I solved it!! It was one of those dumb stupid coding mistakes. In the
event handler for the delete button, I was calling the BindRepeater
method (home grown method to grab the data and bind it to the repeater).
By mistake, I was calling this every time through the loop instead of
just once at the end. Once I moved this to the end of the method, it
worked fine!!

I'm still not exactly sure *why* it was causing a problem, but it was
poor coding and fixing it solved the problem, so I'm happy.

Thank for the help

...and the following code for the button that is supposed to collect
the names of the products to delete...

public void btnDeleteProducts_Click(object o, EventArgs e) {
for (int i=0; i<rptProducts.Items.Count; i++) {
if (((CheckBox)rptProducts.Items.FindControl("chkDelete")).Checked) { .... do stuff here...
BindRepeater(Convert.ToInt32(litCatId.Text), litCatName.Text);
}
}
}
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top