I have an <asp:CheckBoxList>
using RepeatLayout="Flow"
in my page I dynamically assign values to. If the page is loaded the first time (!IsPostBack
), the rendered version looks similar to this;
<span children="Cat">
<input id="ctl00_Menu_Category_0" type="checkbox" name="ctl00$Menu$Category$0"/>
<label for="ctl00_Menu_Category_0">Cat</label>
</span>
<br/>
<span class="Cat">
<input id="ctl00_Menu_Category_1" type="checkbox" name="ctl00$Menu$Category$1"/>
<label for="ctl00_Menu_Category_1"> - SubCat1</label>
</span>
children
is an attribute I use for a jQuery-code, so when the user checks Cat
, all SubCat
s are also checked.
The jQuery code searches for all <span>
s that have the class equal to the child开发者_开发问答ren
-attribute, so I need to maintain this structure that the jQuery works.
But, after I reload the page or follow a link, whatever, the list suddenly looks like this:
<input id="ctl00_Menu_Category_0" type="checkbox" name="ctl00$Menu$Category$0"/>
<label for="ctl00_Menu_Category_0">Cat</label>
<br/>
<input id="ctl00_Menu_Category_1" type="checkbox" name="ctl00$Menu$Category$1"/>
<label for="ctl00_Menu_Category_1"> - SubCat1</label>
How is that even possible? I assigned the values to the list only once, so why is it re-rendered after a PostBack and how can i prevent it from doing so?
Edit
Here is the code that creates the list;
// Get all available categories that are not a child of another category
DataTable categoryParents = functions.SelectSql(Resources.Data.GetCategoryParents);
// Get the child categories
foreach (DataRow parent in categoryParents.Rows)
{
// Add the category
ListItem parentItem = new ListItem(parent["Name"].ToString(), parent["Name"].ToString());
parentItem.Attributes.Add("children", parent["Name"].ToString().Replace(' ', '_'));
Category.Items.Add(parentItem);
// For every parent category, get all its child categories
DataTable categoryChildren = functions.SelectSql(Resources.Data.GetCategoryChildrenByParent.Replace("##PARENTID##", parent["ID"].ToString()));
// Add the child categories after their parents
foreach (DataRow child in categoryChildren.Rows)
{
ListItem item = new ListItem(" - " + child["Name"].ToString(), parent["Name"].ToString() + "\\" + child["Name"].ToString());
item.Attributes.Add("class", parent["Name"].ToString().Replace(' ', '_'));
Category.Items.Add(item);
}
}
Category.DataBind();
jQuery itself doesn't do anything with the HTML, it just holds the functionality for checking children categories when a parent is checked;
$("#Category :checkbox").click(function(){
var checked = $(this).attr("checked");
var children = $(this).parent("span").attr("children");
$("#Category ." + children + " :checkbox").attr("checked", checked);
});
The entire HTML code will always be rendered each time you reload the page. What you can prevent by checking IsPostBack
is changing how the HTML is being rendered this time around. That means that when the page posts back, the server will not bind the checkbox list with new values, but will go directly to render them exactly the way it did last time, using the values that are stored in ViewState.
If your jQuery code alters the HTML after it is being rendered, the server will have no idea and there's really no feasible way of changing that. The interesting question here is: how are the wrapping spans and the children
properties and all that code being applied in the first place?
Your options are to do one of the following:
- Make an AJAX request rather than a full postback, changing only the part of the DOM you want to change
- Re-apply the jQuery code that achieves this change, upon DOMReady after postback
EDIT
In response to the edits in the original post:
Is Category
your CheckBoxList
? If you've iteratively added all list items to it, why do you databind it over again, after that? I think the first for loop should make the databinding obsolete.
My best guess here is that when CheckBoxList
is being serialized to ViewState, it stores the properties applied to it, along with a id/value dictionary for the listitems (and not the additional properties that you apply iteratively).
If it's not being saved in the ViewState - and it looks like it isn't - there are no really clean solutions to your problem. Workarounds would be to execute the code on every pageload, or inherit the CheckBoxList
in a subclass, that overrides the Render
method, to always produce the output you want. In fact that last option might be quite neat, if you're using this a lot throughout the site...?
精彩评论