ASP.NET - losing selection of dropdownlist populated via javascript - asp.net

I have two ASP.NET dropdownlist controls on a page. The first calls back to the server and obtains an array which is returned to the client and used to populate the second dropdownlist via javascript.
However if I make a selection in the second (and newly populated) dropdownlist and then do a postback the selection and contents of the second dropdownlist are lost. This is an issue since I need to obtain the selected value and have the contents of the list retained after the postback.
How do I fix this? I presume it's a matter of updating viewstate at some point before the postback?
The controls I'm populating are ASP.NET dropdownlists. Here is the the javascript I'm using to populate them.
Code being used is as follows (slightly cut down for brevity):
ASP.NET control I'm populating:
<asp:DropDownList ID="ddlStateCounty" runat="server" OnSelectedIndexChanged="ddlStateCounty_OnSelectedIndexChanged" AutoPostBack="true" />
Call back code that obtains comma separated list of values:
public void RaiseCallbackEvent(string eventArgument)
{
return "1, 2, 3";
}
Javascript population code:
function ReceiveServerData(retValue)
{
var statesArray = retValue.split(',');
var statesList = document.getElementById('{0}');
if (statesArray.length > 0 && statesList != null)
{
for (var j = 0; j < statesArray.length; j++)
{
var newOption = document.createElement('OPTION');
statesList.options.add(newOption);
newOption.value = statesArray[j].toString().trim();
newOption.innerText = statesArray[j];
}
}
}

You're correct in stating that you don't have the ViewState right, which is why the values aren't populated when you post the data back to the server.
I would strongly recommend that you migrate to using the Cascading Drop Down within the ASP.NET AJAX Control Toolkit (it has both .NET 2.0 and .NET 3.5 releases), as it does what you are after and it does maintain via the postback.
Your other option would be to have an onchange event on the JavaScript-populated drop down list in which you then populate a hidden field, as that will be posted back to the server and the value of the submit will be maintained within the posted data, something like:
$addHandler('change', $get('dynamicDDL'), function () { $get('hiddenField').value = this.options[this.selectedIndex].value; });
For the demo I used the MS AJAX short-hand for adding events, etc. More info on the methods I used can be found here: http://msdn.microsoft.com/en-au/library/bb397536.aspx

Request.Form[Control.UniqueID] gives you the selected value.

just use response.forms collection to get the selected value.

I'm guessing that "you aren't doing things the asp.net way".
It seems likely to me that if your javascript modifications aren't native asp.net then the elements you're populating aren't asp.net controls so you're losing them in the postback. asp.net really demands a tight binding between it's model and the actual page.
Could be way off base though - would help if you could post some code. (the JS and the codebehind method)
edit for new info:
Right - so you're basically creating a load of perfectly normal html elements through JS alone based on an AJAXified return string(?), which the asp.net codebehind has no concept of whatsoever. I'm not 100% sure this is the problem without setting up a test app myself, but it sounds about right.
Inspecting Request.Forms then - as others have suggested - is going to be the simplest way to fix this right now, but you should keep in mind that asp.net gets more and more painful the further you stray from doing things the way it wants you to. I think it would be worth working out how to add these new options from the codebehind.

try this code
Request.Form[Control.UniqueID]

Related

Failed to load viewstate. The control tree into which viewstate is being loaded

I am receiving the following error message after an HTTP POST on an ASP.NET form hosted inside a UserControl:
Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate during the previous request. For example, when adding controls dynamically, the controls added during a post-back must match the type and position of the controls added during the initial request.
Here's additional info:
I'm running .NET 4.5 RC
It's an Umbraco 4.7-based website
On my local dev machine the form works perfectly
This error only occurs on the staging server which has .NET 4.5 (only), MSSQL 2012 Express, IIS 7.5, Windows 7 (I know, it's not a real server yet, one day maybe...)
The server is not part of a web farm (or garden, tho that should be irrevelant)
The user control does render controls dynamically
I have applied all the latest service packs.
I have run out of ideas now! I have even restarted it and also performed a richual over the server involving a song and a special dance to no avail.
What is important when you are adding controls dynamically is on which event you are adding them.
If you added controls on events that occur after load, they will be part of the viewstate you send to the client.
You will have to add those controls again before LoadViewState is called.
If you run into cases where the decision of which controls to add is itself stored in the ViewState or the value of a control, then remember even before the ViewState is loaded, this data is available in Request.Params
Refer the asp.net page life cycle
I just added EnableViewState="false" to my page placeholder and its gone. Hope it works for u as well.
This Error Mainly Occurs during View state Change: From One Template To other Template like in case of Item Template, Edit Item Template, in Controls like Form View, List Views, Detail View, Grid View in ASP .net (all frameworks);
While Changing from control states say Item Template ---> Edit Template
the followings were going to alter
1) Controls will change (its ID & states)
2) Its Positions will change.
While Transformation of view if any post back occurs you will get Error as
Failed to load viewstate. The control tree into which viewstate is
being loaded....
if you are using separate control for data-binding like (button,link_button_Image_button events) you will get this error reported !
To avoid this error >>> Once state changes from one template to other within method you call data source binding ( Don't call during click or any post backing events ).
OK, so the answer is literally: "Set up a new server with all the same software as the last one and try again" and it works now.
I add "name" attribute with the same value as id, then this problem is gone.
<input type="button" id="extractBomInfoBtn" name="extractBomInfoBtn" value="Extract" class="button textonly" />
I had the same issue. This issue was at client end but it didn't occur in my local system.
After hours of googling, i had written EnableViewState="false" to my table tag in aspx page which has all the dynamic controls and then i removed all the viewstate variables and instead i created some hidden textboxes in the aspx page and accepted DB values into them in code behind and used them throughout my code. It then solved my problem.
But still, i couldn't figure out what was exactly the problem.
In my case I was manipulating the .Text property of a asp:Literal on page load which was causing the issue. In all other cases this never caused me a viewstate error but in this particular case I was changing the .Text value to an html element.
The following caused the error:
<asp:Literal ID="SvgIcon" runat="server" />
SvgIcon.Text = "<svg version=\"1.1\" id=\"Layer_1\" bla bla />"
I was able to resolve the error by adding EnableViewState="false" explicitly to the control:
<asp:Literal ID="SvgIcon" runat="server" EnableViewState="false" />
Check if you have the binding method of the control directly in your page load event. This can cause this problem.
You can add new PlaceHolder per UserControls
OR
You can set enableviewstate=false on the control , if you dont need viewstate
In my case I had a grid view with (OnPageIndexChanging) event
and when I click on a page nothing will happen until I click it twice!
I was refreshing the data source before setting new page index.
This is what I was doing wrong
grd.DataSource = data;
grd.DataBind();
grd.PageIndex = e.NewPageIndex;
This is the right way
grd.PageIndex = e.NewPageIndex;
grd.DataSource = data;
grd.DataBind();
This can happen if you override SaveViewState in your control but don't override LoadViewState.
So I actually ended up discovering that the list of entities I was binding to was not in the same order as the controls in ViewState! I'm still working thru a cleaner solution, but my code is working with ViewStateEnabled = true by having the method which reconstructs my dynamic controls (called from Page_Load) do it differently if !IsPostBack.
Ultimately, I will probably need to fix my sorting algorithm for my nested dynamic controls, but suffice it to say: if you are using the same pattern as I am, of using a List to generate/bind to dynamic controls, and that order is fluid or changing, try comparing Request.Params to find the keys that are relevant to your control hierarchy, and see if they match the order of your List. That solved my issue. Kudos to #nunespascal!
In short, I am dynamically generating all but one tab in an AjaxToolkit tab control, and then populating that with a couple layers deep of placeholders and regular controls (textboxes, dropdownlists, etc), so that's why it's complicated to get the order of everything correct.
Although this is very old question, I had visited this as I got the similar issue. But my issue was generated just because I have added a javascript code in Master page in head tag. That javascript code is reading a value of Session["KeyName"] ,
Code is like below -
$(document).ready(function () {
var allowOpenInNewTab = false;
allowOpenInNewTab = '<%# Convert.ToString(Session["AllowOpenInNewTab"]).ToLower() %>' == 'true';
if (!allowOpenInNewTab && window.sessionStorage.tabId != '1') {
alert("This page is not allowed to be open in another tab, sorry we can not load the page!!");
}
});
When I remove above code then everything was running smoothly but if I keep adding this part of code, it was giving this error of
Failed to load viewstate. The control tree into which viewstate is being loaded must match the control tree that was used to save viewstate...
Finally I found the solution like if I move my javascript code from head to just before the end of the body tag.
So solution that worked for me was moving javascript code (which is reading Session value from Server tags) to just before end of body tag.

Webforms ReportViewer pagination without showing the toolbar?

I am looking into replacing the ReportViewer toolbar. Just doing discovery right now. I know about the JavaScript api for the report viewer. This does not include an API for the pagination controls.
I have dug around in the generated HTML and have figured out how to trigger a postback to do the pagination. Calling the following in Javascript works even with the toolbar not being displayed.
__doPostBack("ReportViewer1$ctl05$ctl00$Next$ctl00")
I don't know the gotchas of calling a post back like this. As the string being passed into the method is the name of the input button. It seems like the name may be able to change. I also don't know what the $ctl stuff means.
I am aware of how to get reportviewer to not page reports by setting the interactive height to zero. I am just exploring all my options at this time.
Is there an easier way to do pagination without the ReportViewer toolbar being displayed? If not, what are the gotchas of triggering a postback?
The final solution to this was to do a postback with customer arguments.
Client Side JS:
function loadPage(pageNumber) {
$('#__EVENTTARGET').val('pagination');
$('#__EVENTARGUMENT').val(<pageNumberToGoTo>);
$('#form1').submit();
}
The two fields that get populated are what is created by default for ASP.NET postbacks.
Server Side C# in the ASP.NET pages OnLoad event:
if (Request.Form["__EVENTTARGET"] == "pagination")
{
int pageNumber = int.Parse(Request.Form["__EVENTARGUMENT"]);
_reportViewer.CurrentPage = pageNumber;
}

SelectedIndexChanged event dont fire when create a dropdownlist in code-behind

For two day i try to solve this issue.
I create a dropDownList in code-behind, in selectIndexChange of another dropDownList, and add this new dropDownList to page using a placerHolder, everthing its ok, but new dropdownlist selectIndexChange event dont fire!
code of dropDownList creation
dropDown = new DropDownList();
dropDown.AutoPostBack = true;
dropDown.ID = idSubistema;
dropDown.Width = 400;
dropDown.CssClass = "controltext";
dropDown.DataValueField = "IDNivel";
dropDown.DataTextField = "NIVEL";
dropDown.EnableViewState = true;
dropDown.DataSource =
DBLibray.DefinitionIndicadores.spSelect_FillCombosWithNivelByIdParent(
ref dataConnector,
Convert.ToInt32(idSubistema));
dropDown.DataBind();
dropDown.SelectedIndexChanged += new EventHandler(indexChange);
//dropDown.PreRender += new EventHandler(dropDown_PreRender);
placeHolderForCombos.Controls.Add(new LiteralControl("<div>"));
placeHolderForCombos.Controls.Add(lb);
placeHolderForCombos.Controls.Add(new LiteralControl("<br>"));
placeHolderForCombos.Controls.Add(dropDown);
placeHolderForCombos.Controls.Add(new LiteralControl("</div>"));
placeHolderForCombos.Controls.Add(new LiteralControl("<br>"));
Can't anybody help with this??
Thanks
You are making things really hard for yourself by creating controls in this way. Although ASP.Net WebForms pretends to work like WinForms by raising events and such, it isn't. HTTP is a stateless protocol. Therefore, every time a user requests an ASPX page, every postback, the entire page needs to be re-constructed by ASP.Net.
There is a page lifecycle that gets run through (init, load, pre-render, etc), and if a control is not created in this lifecycle, it won't exist, and won't be rendered to the client. By creating controls "dynamically" in the way that you're doing, you need to make sure they get created at the right time, every time the page is loaded. This method also makes dealing with Viewstate a little more tricky, and it's a pain anyway.
You might have a really complicated page that makes creating controls like this absolutely necessary, but it's more likely that you'll be better off writing your second drop-down list in the ASPX markup in the normal way. This will ensure it's always available to use. You can then conditionally databind to it, and toggle its Visible property. If this property is false, the control won't be rendered to the client at all.
In general with ASP.Net, if you're creating controls in this way, it's a sign that you're over complicating matters. Not always the case, but more often than not.
You are creating new dropdown in event "selectIndexChange". it's too late. Try to create dropdown in Page_Load or databinding event. use visibility to show/hide your ddl "idSubistema"

JQuery and ASP.NET Web Forms

I am creating a ASP.NET Web Form application where I am trying to use some nice jQuery functionality and flashyness. The current part of the application I have consists of two jQuery UI tabs; a search tab and a results tab. When the user performs a search from the search page, the results tab will be selected and the results will be displayed in this tab. I need to get the results into a gridview. Now this is where the issue starts to come in:
The easiest way to get the search results is to allow the search click to perform the postback where I can then format the datasource with the parameters from the input fields and let the datagrid take care of itself and data bind and show the results. The thing is, this really doesn't look that great (due to the whole post back and such) as well as starts to cause some issues with using javascript/jQuery to take care of tab switching and all that portion because the postback reinitializes everything from the jQuery UI (i.e. the jQuery UI tabs). So in short, the postback allows for easy binding of the input for the search and getting the results, but makes the page and its behavior all wonky.
I was wondering if there is a standard way to do this type of mixing jQuery/javascript/AJAX all together within web formto get the functionality of things like the gridview and such. I am wondering if there are some good tutorials, or even just a direction on solving this issue.
I hope all this made sense, and thank you all for your help.
I don't think this is a standard, but here is the pattern I use:
First of all, I use Page Methods for ASP.Net to get hooked back up to the server. In this case it would be something like this:
PageMethods.Search(searchValue, onSearchComplete);
That calls a static page method in the page, like this:
public static void Search(string searchValue)
...
Inside that procedure, I create an instance of a user control which contains the gridview, and invoke a method on that control, passing the searchValue:
var searchControl = (SearchControl)new SearchControl().LoadControl("/controls/SearchControl.ascx");
searchControl.Search();
var stringBuilder = new StringBuilder();
using (var textWriter = new StringWriter(stringBuilder))
{
var htmlWriter = new HtmlTextWriter(textWriter);
searchControl.RenderControl(htmlWriter);
return stringBuilder.ToString();
}
This is all going to end up as the result argument to the handler you specified in the initial call (onSearchComplete) in this example. You can do whatever you want with the markup, including slapping it into a div, or alerting it for debugging.

ASP.Net: Why aren't the changes I make to Viewstate in a control event available to subsequent postbacks?

I'm writing a custom control in ASP.Net 3.5 WebForms, using ASP.Net AJAX. I'm building a state toggle into the control (expanded and collapsed modes). I've been trying to keep the current state of the control in ViewState, changing it in a server-side event handler manually:
object oExpanded = ViewState[ "Expandedness" ];
if(oExpanded == null)
{
oExpanded = ListState.Collapsed;
}
ListState lsCurrentState = (ListState) oExpanded;
if(lsCurrentState == ListState.Collapsed)
{
//code snipped - move to expanded mode here
ViewState[ "Expandedness" ] = ListState.Expanded;
}
else
{
//code snipped - move to collapsed mode here
ViewState[ "Expandedness" ] = ListState.Collapsed;
}
I don't think it should matter, but the actual rendering happens in an updatepanel and the code above is in an event handler that's triggered asynchronously. The problem I have is that on the next postback, ViewState["Expandedness"] returns null. I've tried to use Fritz Onion's Viewstate Decoder tool to look at the actual contents of viewstate between postbacks, but it tells me the serialized data is invalid.
Have I taken a wrong approach here? What's the right way to tackle this problem?
You're right that it's OK for it to be in an UpdatePanel - this shouldn't make any difference.
I suspect that the ViewState is disabled either for your control or for one of its parents: if it's disabled for any parent (all the way up to the page), it'll be disabled for your control.
To get round this, you can use the page's ViewState dictionary instead of the one on your control.
I.e. instead of saying:
this.ViewState[ "Expandedness" ] = ListState.Expanded;
say:
this.Page.ViewState[ "Expandedness" ] = ListState.Expanded;
If it's possible that there's more than one instance of your control on the page, you'll need to ensure the ViewState key is unique, perhaps like this:
this.Page.ViewState[ this.ClientID + "Expandedness" ] = ListState.Expanded;
As an alternative (that will work even if ViewState's disabled for the page), you could consider storing the Expandedness in the ControlState. It's a bit trickier, but google it and you'll find a code sample pretty quickly. It's recommended you store only an absolute minimum of information in the ControlState, but a single flag like this is fine (and actually what it's designed for, really).
when do you call this code? if it is called in Page_Init it is too early, and any changes you do to the viewstate will be ignored.
Just a thought
Further investigation: The changes to Viewstate that I make in the sub-control event handler do last as long as Page_Prerender (i.e. later in the event lifecycle of the page), so the problem isn't that Viewstate isn't getting written to. But any subsequent postbacks to the page - synchronous or asynchronous - don't show that value in viewstate.

Resources