ASP.Net RadioButton loses ViewState - asp.net

I'm having trouble with a simple radio set of two radio buttons (I don't want to use a RadioButtonList [RBL] because RBL doesn't allow child controls, and in my case, if you select one option, I want to enable a textbox next to the button; yes you could hack this with jQuery to move the textbox, but that's dirty!). I would check one, submit the form (either explicitly or through AutoPostBack), and the CheckedChanged event would never fire. When the page was reloaded, both buttons would be unchecked, regardless of their initial state on non-postback load or the state before form submission.
I took out the checkbox and stripped this down to the simplest example I could come up with. I tossed EnableViewState=true all over the place just in case it was being disabled somewhere I couldn't find.
<form id="form1" runat="server" enableviewstate="true">
<div>
<asp:RadioButton ID="foo" Text="foo" runat="server" AutoPostBack="true" OnCheckedChanged="rbChanged" Checked="true" GroupName="foobar" EnableViewState="true" />
<asp:RadioButton ID="bar" Text="bar" runat="server" AutoPostBack="true" GroupName="foobar"
OnCheckedChanged="rbChanged" Checked="false" EnableViewState="true" />
<asp:Label runat="server" ID="resultLbl" />
</div>
</form>
protected void rbChanged(object sender, EventArgs e)
{
if (foo.Checked) resultLbl.Text = "foo is checked";
else if (bar.Checked) resultLbl.Text = "bar is checked";
else resultLbl.Text = "neither is checked";
}

It turns out this was because we had a custom adapter rendering the HTML for a radiobutton (or to be precise, for all System.Web.UI.WebControls.CheckBox es). Our motivation for this was because .NET will put a disabled="disabled" attribute on the LABEL and the input, which is bad HTML, and worse, is actually interpreted to mean something by IE! (Check it out for yourselves -- write up an HTML page with a label disabled="disabled" and test in FF and IE.)
We used Reflector to see what step we were mixing up vs what the real adapter did, and found that the Name attribute was being set incorrectly. Although it set all the RBs in a given group to the same Name, it was not the same Name attribute in our limited new-solution test case as it was in our custom-adapter test case. When we looked at how to generate that safely, we found that our postbacks suddenly worked!
If we get permission from the boss, we'll contribute our adapter to CSSFriendly in case anyone else has use for this sort of thing.

I've tested your exact code and it works fine. When you select either radio button, the lable is updated during postback and correct information is shown when the page refreshes??

In some cases the issue may be caused by ScriptManager in code-behind.
For e.g.
ScriptManager.RegisterStartupScript(this.Page, this.GetType(), "DisplayMessage", "javascript: HideProcessingImage();", true);
Using the same key name in different methods as above may be the issue of radio button autopostback not working.
I've faced this issue so anyone with same issue can solve their problem.

Related

Disable control while post back is happening

I'm working with a telerik grid made in a user control, inside this control there is a checkbox
<telerik:GridTemplateColumn>
<ItemTemplate>
<asp:CheckBox ID="check" AutoPostBack="true" runat="server" OnCheckedChanged="check_CheckedChanged"/>
</ItemTemplate>
</telerik:GridTemplateColumn>
What I need to do is while the "check_CheckedChanged" is happening disable a certain button that is outside the user control (i know this defeats the purpose of the control being independent but that's not something I can change now). This is because the check_CheckedChanged takes too long to execute (as it does a lot of validations) and the user can press the button before its disabled by the result of check_CheckedChanged. By the way, I do have the buttons id in the control if that's info someone needs.
A less than ideal situation, as you've pointed out, but you could use Javascript. In the check_CheckedChanged, write out a Javascript call to a hideButton() function, which is outside of the user control.
ScriptManager.RegisterStartupScript(Page, Page.GetType(), "script", "hideButton();", true);

asp:checkedchanged event not firing?

there. I have a gridview with a column of check boxes which was working when it was a small test project but when adding it to a page on my teams project it stopped firing the checkedChanged event. The check mark still appears or disappears but nothing fires. The only major difference is I was using an sqlDataSource object at first but for the new project i had to bind it to a database in the behind code.
Here's my html:
<asp:TemplateField HeaderText="Create Incident">
<ItemTemplate>
<asp:CheckBox ID="Selections" runat="server" ViewStateMode = "Enabled" OnCheckedChanged="CheckBox1_CheckedChanged" />
</ItemTemplate>
</asp:TemplateField>
and some simple behindcode:
protected void CheckBox1_CheckedChanged(object sender, EventArgs e)
{
Console.WriteLine("clicked!");
}
set AutoPostBack to True to enable post back
<asp:CheckBox ID="Selections" runat="server" ViewStateMode = "Enabled" OnCheckedChanged="CheckBox1_CheckedChanged" AutoPostBack="True" />
I found the solution. I added the conditional the block if(!page.isPostBack) around the stuff in my page load event.
Kept searching for about an hour till I found out that the actual reason why the OnCheckedChanged event was not firing on my page was due to duplication of names. Duh
An input control had a name 'submit' and there also exists a method in my JavaScript that is called submit(). The JavaScript interpreter was confused between the name of the control and a function, every time it needed to fire the event. Changed the name of the control and everything went back to working perfectly.

Why does a failed validation prevent postbacks from control in other validation groups?

I have an asp.net web form with several textboxes, buttons, and other controls. One of the buttons is supposed to trigger validation of content in some of the textboxes. This works fine, except that if validation fails, all subsequent postbacks of the page are prevented. Fixing the invalid values gets rid of the error messages, but postback still does not occur.
The validation is occurring within an AJAX UpdatePanel. I'm not sure if that matters or not.
I'm glad the workaround is fine for you, but for the benefit of others who land this page, disabling client side validation is far from an acceptable solution. So here goes:
Why it happened only when UpdatePanel was around, is still unclear to me, however:
As others have mentioned, the issue you were having is most likely because the unsuccessful validation attempt is preventing a further postback.
See also: Why won't my form post back after validation?
There is a variable called Page_BlockSubmit which is set to true when client side validation fails:
function Page_ClientValidate(validationGroup) {
....
Page_BlockSubmit = !Page_IsValid;
return Page_IsValid;
}
So when a __doPostBack occurs as part of, say, an OnSelectedIndexChanged of a DropDownList, there is this check:
function ValidatorCommonOnSubmit() {
....
var result = !Page_BlockSubmit; /* read the value */
....
Page_BlockSubmit = false; /* reset it */
return result;
}
Which will block the first time, but then clear the flag, so the next postback attempt should work.
The workaround, in my case, for a DropDownList's OnSelectedIndexChanged event, was to have a snippet added to its client-side onchange event:
<asp:DropDownList runat="server" ID="SomeDropDownList" OnSelectedIndexChanged="AlwaysDoSomething"
onchange="resetValidationState(this);">
....
</asp:DropDownList>
<script type="text/javascript">
function resetValidationState() {
// clear any postback blocks, which occur after validation fails:
window.Page_BlockSubmit = false;
}
</script>
You might get away with putting that snippet into the onchange itself.
except that after this button has been clicked no other button can cause a postback unless the validation errors have been corrected. So, btnDelete, which should not require validation of the textboxes, cannot postback until the textbox values are corrected
Don't see that behavior with following code..
<asp:TextBox ID="TextBox1" runat="server"></asp:TextBox>
<asp:RequiredFieldValidator ID="RequiredFieldValidator1" runat="server" ErrorMessage="RequiredFieldValidator" ControlToValidate="TextBox1" ValidationGroup="pc">
</asp:RequiredFieldValidator>
<asp:Button runat="server" ID="btnSubmit" Text="Submit" Width="150" CausesValidation="true" ValidationGroup="pc" />
<asp:Button runat="server" ID="btnDelete" Text="Delete" CausesValidation="false" />
I could be totally off base here - but i think I see the problem. (I work mainly with devexpress controls so the rules can be a bit different). When validation fails, the whole page is set to invalid, so no postbacks can occur. Can it be since the delete button is not causing any validation, its not re validating after those editors have been changed to be valid?

RequiredFieldValidator have to click twice

I have run into the same problem as described here.
Only the question is marked as answered with only an explanation as to why you may have to click twice when using a RequiredFieldValidator on input fields - once as the blur of a textbox(for example) will correct the validation and then again to actually post the form.
I don't want to have to click a button twice! Does anyone know a solution or workaround to this?
You could add EnableClientScript=false to the validator.
That prevents the client-side validation, so you will always get a postback (which may not exactly be what you want, though). The validation will still be done, just server-side.
Be sure to wrap the button-click logic in a if (Page.IsValid) { ... }, to check the status of the validators.
Apologies for not posting code previously I assumed this to be a standard problem with the RequiredFieldValidator, but have since realised my particular problem was coming from a CompareValidator, used to ensure entered passwords matched.
The CompareValidator was causing the issue that I described, causing me to have to click away from the field to blur and validate, before being able to click on the post button.
I'm not sure why but changing the Display of the CompareValidator from Dynamic to Static has cleared the problem up.
If the validator is Display="Dynamic", and the appearance of the error message causes the submit button to move, then the MouseUp event is not received by the submit button. In this case, the validation fires and clears the error message, but the submit button does not fire. To solve the problem, either set the the validators to be Display="Static", or rearrange the form so that the submit button does not move when error messages appear.
Here's a way to reserve about one, vertical line of space for a dynamic validation message:
<div style="height:1.5em;overflow:visible;">
<asp:RequiredFieldValidator ID="R1" runat="server"
ErrorMessage="Name is required" ControlToValidate="TextBoxName"
Display="Dynamic"></asp:RequiredFieldValidator>
</div>
I did not find it necessary to set EnableClientScript="false", although that did help for a CustomValidator that had no client-side validation function implemented.
Posting your code is always a good idea, That way we could run your code in a test environment and modify it to ensure it works before posting our answer.
I would suggest adding
causesValidation="true"
to your button to see if that works.
I have a better idea.
Add Text="" to textbox Control.
Add InitialValue="" to Validator Control.
What it will do, when it will be posting, it will find the value of the text box is still the initail value and it will throw an error and the form will not be posted.
Try this:
<asp:RequiredFieldValidator ID="reqFieldCloseComment" ControlToValidate="tbCloseComment" ValidationGroup="ChangeStatus" ErrorMessage="Please enter a reason" Display="Dynamic" runat="server" InitialValue=""></asp:RequiredFieldValidator>
<asp:TextBox ID="tbCloseComment" runat="server" CausesValidation="true" TextMode="MultiLine" Height="107px" Width="400px" Text=""></asp:TextBox>
<asp:Button ID="btnCloseRequestFinal" Text="Finish" CssClass="CloseReqButton" runat="server" ValidationGroup="ChangeStatus" />
Here is code that is working fine for me and helping to get rid of double click.
<asp:TextBox ID="TextBox1" runat="server" autocomplete="off"
Enabled="true" MaxLength="20" onfocus="SetActiveControl(this);" Text=""
CausesValidation="true" />
<asp:RequiredFieldValidator ID="RequiredFieldValidator1"
runat="server" ControlToValidate="TextBox1" Display="Static" ErrorMessage="Ha!" SetFocusOnError="True" EnableClientScript="true" ForeColor="" InitialValue="" />
$(function() {
$("input.btn").on("click",function(){
if(Page_BlockSubmit == true) {Page_BlockSubmit = false};
})
});
Page_BlockSubmit is a JS variable defined by the js generated from code behind when you define the validator . I haven't went deeper to know why MS need this variable, but the scenario is:
the first click will make Page_BlockSubmit become false.
the second click will check the value of Page_BlockSubmit and return true.
if you implemented the code I posted, every time you click the button, the variable will be set as false which will trigger the submit at every click.
And, you can use google chrome to trace the value of Page_BlockSubmit.

One user control updating another during AJAX Postback?

I developed a user control that displays a list of products and it works pretty good. Then I dropped this user control into another user control that allows the user to pick different criteria and the product UC updates to show those products, all pretty slick and with AJAX via UpdatePanel.
All was working just fine... then another requirement came in. The "search" control needs to be separate from the product control (so they can be positioned separately). Initially, I thought this was no problem as I would give the search control a reference to the product control and then it would talk to it via reference instead of directly inside the control (which has been removed).
And they do talk. But the product control loads, but refuses to display.
I checked and it is being passed via reference and not a copy ( as best I can tell ).
There is an updatepanel in the search control. There is an update panel in the product control. And then for good measure, there is an update panel surrounding them both in the actual search aspx page.
I've tried setting the product control update panel to conditional and then fire the .Update() method manually.
What's the secret here?
TIA!
SOLVED
Thanks to Jamie Ide for the tip to use events.
Search Control and Product control still have internal update panels, and NO LONGER have them on this particular page.
Search Control now raises an event OnSearchResultsUpdated and exposes the found items in properties. The page subscribes to this event and takes the properties and passes them to the product control and triggers triggers a .Refresh() method on the product control which simply calls the .Update() on its internal updatepanel.
The Product control, FYI, accepts products in several different flavors. A list of distinct SKUs, a list of product ids, a named collection in our database and finally a given product category.
Our designers need to be able to create a new page, drop the control onto it and set some properties and voila! New site page. They don't want to require a programmer's involvement. So keeping the controls self contained is a requirement. Fortunately all the changes I made still work completely with the other uses of the product control.
THANKS AGAIN SO MUCH!
I don't think there's really enough information to work with here, but my best guess is that the Product control is not getting data bound. You may try calling myProdcutsCtrl.DataBind() from the search control (or something inside the Product control that cause a DataBind() for instance myProductCtrl.Search(value1, value2, value3).
One other thing you might try is removing the UpdatePanels and seeing if things work. Then add them back in once you get core functionality going.
UPDATE: I've gone ahead and put some example code that works here which I believe accomplishes what you want. What follows are snippets for the sake of saving space, but include all code necessary to make it run. Hopefully this will at least give you something for reference.
Things to try:
EnablePartialRendering="true|false" setting it to false will force the natural postbacks and is good for debugging UpdatePanel problems.
Make sure you are seeing Loading... come up on your screen. (maybe too fast depending on your dev computer)
Page.aspx
<%# Register Src="~/Product.ascx" TagPrefix="uc" TagName="Product" %>
<%# Register Src="~/Search.ascx" TagPrefix="uc" TagName="Search" %>
...
<asp:ScriptManager runat="server" ID="sm" EnablePartialRendering="true" />
Loaded <asp:Label ID="Label1" runat="server"><%= DateTime.Now %></asp:Label>
<asp:UpdateProgress runat="server" ID="progress" DynamicLayout="true">
<ProgressTemplate><b>Loading...</b></ProgressTemplate>
</asp:UpdateProgress>
<uc:Search runat="server" ID="search" ProdcutControlId="product" />
<uc:Product runat="server" ID="product" />
Search.ascx
<asp:UpdatePanel runat="server" ID="searchUpdate" UpdateMode="Conditional" ChildrenAsTriggers="true">
<ContentTemplate>
<p>
<asp:Label runat="server" AssociatedControlID="filter">Less than</asp:Label>
<asp:TextBox runat="server" ID="filter" MaxLength="3" />
<asp:Button runat="server" ID="search" Text="Search" OnClick="SearchClick" />
</p>
</ContentTemplate>
</asp:UpdatePanel>
Search.ascx.cs
public string ProdcutControlId { get; set; }
protected void SearchClick(object sender, EventArgs e)
{
Product c = this.NamingContainer.FindControl(ProdcutControlId) as Product;
if (c != null)
{
c.Search(filter.Text);
}
}
Product.ascx
<asp:UpdatePanel runat="server" ID="productUpdate" UpdateMode="Conditional" ChildrenAsTriggers="false">
<ContentTemplate>
<asp:Label runat="server">Request at <%= DateTime.Now %></asp:Label>
<asp:ListView runat="server" ID="product">
<LayoutTemplate>
<ul>
<li id="itemPlaceHolder" runat="server" />
</ul></LayoutTemplate>
<ItemTemplate>
<li><%# Container.DataItem %></li></ItemTemplate>
</asp:ListView>
</ContentTemplate>
</asp:UpdatePanel>
Product.ascx.cs
IEnumerable<int> values = Enumerable.Range(0, 25);
public void Search(string val)
{
int limit;
if (int.TryParse(val, out limit))
product.DataSource = values.Where(i => i < limit);
else
product.DataSource = values;
product.DataBind();
productUpdate.Update();
}
Code does NOT represent best practices, just a simple example!
I'm fairly new to AJAX, but I don't think it's a good idea for user controls to have UpdatePanels. I would also advise you not to have the user controls reference each other; they should communicate through events and methods controlled by their container.
I do something similar with two user controls for a master-details display. The master raises an event when an item is selected from a list, the containing page handles the event and calls a method on the details display to display the selected item. If I remember correctly, my first attempt had UpdatePanels in the user controls and I wasn't able to make that work. Having the user controls inside an UpdatePanel on the page works fine.
If I understand you right you have a layout like this:
Outer UpdatePanel
SearchControl
Search UpdatePanel
ProductControl
Product UpdatePanel
Databound Control
Which one of those update panels is actually being called?
I assume that if you check the network traffic with something like Fiddler or Firebug if you're using Firefox, you aren't seeing any HTML for the product update panel coming back?
Have you tried doing something like:
UpdatePanel productUpdate =
Page.FindControl("Product UpdatePanel") as UpdatePanel;
if (null != productUpdate){
productUpdate.Update();
}
By default, if a postback is made from an UpdatePanel, only that control will be updated/re-rendered (this is called partial page-rendering).
To also update/re-render other UpdatePanels, you have to either:
set their UpdateMode property to Always
add the control that makes the postback to their Triggers collection
Check this page in MSDN for details.

Resources