Much like when you are looking for support on a website or whatever, you choose Product from the first listbox (say, Hard Disk), which triggers and populates a second listbox with more options (say, "Solid State", "SATA"), and so on...
The problem I am having is that when you select something from the second listbox that should populate the third one, the postback triggers the first listbox too, which then repopulates the 2nd one back to its default value.
Eg.
[Dropdown 1] (contains A B C D E)
[DropDown 2] (A in dropdown 1 has options X Y Z)
[Dropdown 3] ...
If you choose A, then dropdown 2 populates with XYZ. You choose Z, and it should update dropdown3, but the postback also triggers dropdown 1 again, which replaces Dropdown 2's contents and resets the value back to X.
I am looking for an elegent solution. I had one that said only repopulate dropdown 2 if dropdown 1 has changed, but it means keeping track of what dropdown 1 was before the page posted back.
Each dropdown is in an updatepanel and set to autopostback=true, and each updatepanel has the previous listbox in its triggers.
First Check if the second TextBox isn't a trigger to the first UpdatePanel, if it is then remove it from the first update panel's Triggers Collection.
Here's the Key Concept:
If you have two separate tags you should place a trigger tag in the second update panel and insert a AsyncPostBackTrigger with the controlID of the first dropdownlist, here's a simple example:
<asp:UpdatePanel runat="server">
<ContentTemplate>
<asp:Label runat="server" ID="TxtBox1" />
</ContentTemplate>
</asp:UpdatePanel>
<asp:UpdatePanel runat="server">
<ContentTemplate>
<asp:Label runat="server" ID="TxtBox2" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="TxtBox1" />
</Triggers>
</asp:UpdatePanel>
I would simply put all the drop downs in the same update panel. It might not be as efficient, but it will probably bee good enough and certainly require less lines of code.
Why don't you try AjaxControl Toolkit CascadingDropDown. It seems to suit your needs.
Also, this will improve performance, as postback won't be sending all page information (as does with update panel).
I figured it out - I can use ScriptManager1.AsyncPostBackSourceElementID to check what caused the trigger, and make it refresh only for postback and the first dropdown box.
Maybe I'm thinking too simplified, but why wouldn't you just be handling all these events ... as events? Populate DDL1 only on initial Page_Load. Populate DDL2 only on DDL1.SelectedIndexChanged. Populate DDL3 only on DDL2.SelectedIndexChanged...
Related
I reference a previous post: Focus lost on partial postback with UserControls inside UpdatePanel
where an excellent solution works perfectly for web-page controls within a form.
However, I have placed my UC inside a detailsview template-field (for Edit+Insert).
The UC contains an UpdatePanel needed to adjust the text-formatting and control's style(s) following the TextChanged event of the UC-textbox (AutoPostback=True) during the Edit-mode and Insert-modes of the DetailsView.
As such, when the DetailsView-control is in Edit-mode, and user changes Text in the UC, the textchanged event is fired and the user-entered value is validated and when OK, the thousounds-separator (comma) are added to the UC-textbox-text, BUT, the focus moves to the next field in the DetailsView and QUICKLY returns back to the UC-control.
This incorrect focus-move(s) does NOT occur when the UC is wrapped in updatepanels as noted in the referenced post since the focus and tabbing order works perfectly outside of the DetailsView control.
Here is the aspx markup for the template-field-EDIT (only).
<asp:TemplateField HeaderText="Initial Mileage" SortExpression="IMilage">
<EditItemTemplate>
<asp:UpdatePanel ID="updpnlIMilage" runat="server" UpdateMode="Conditional" >
<ContentTemplate>
<TGANumeric:GANumeric ID="ucnumIMileage" runat="server"
Caption="Initial Mileage" HideCaption="True" Width="160"
DisplayMask="999,999" InputMask="999999"
Enabled="True" IsRequired="False"
MinNumber="0" MaxNumber="999999"
Text='<%# Bind("IMilage") %>'
TabIndex="0"
/>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="ucnumIMileage" />
</Triggers>
</asp:UpdatePanel>
</EditItemTemplate>
Thanks in advance. Your comments are welcome.
Thanks...J.
So are you saying your control hierearchy (partial) is:
UpdatePanel > TGANumeric:GANumeric > UpdatePanel > TextBox
This is an awful lot of overhead to just format a number with a comma, which is the only reason I see for your posting back. As far as I can tell there is nothing you need from the server, so why post?
Or is there?
My thoughts, lose the update panels, disable the AutoPostback on the Textbox, handle the formatting client side if it must be seen immediately, or leave the formatting to the DetailsView field DataStringFormat when it posts after save.
I'm betting this will clear up any focus issues.
Based on all the comments in this thread, I want to explain the actual root cause of the tabbing misbehavior.
1) There were no coding issues or event-issues with the user-control.
2) There were no coding issues or event-issues with the layering of Master-page, Content-page, Ajax update-panels / nested update-panels, details-view and template-fields containing the user-control.
3) The real culprit was a small snippet of code where the page adjusts the web-controls on the form based on the "state" (status) of the page/form. I manage the adjusting of visible and/or enabling of web-controls in a single subroutine in the code-behind so that all of this enabling/disabling visible/not-visible occurs in one place under a set of CASE-statements.
The actual erroneous snippet of code inside the 'sbSetFormState()'-method was messing with the class-variable 'm_eFormState' that actually caused the update panel to re-fire and thus the tabbing got thrown out of sequence.
This was discovered by the great suggestion from 'fnostro' to remove or add functionality features until the mis-behavior exposes itself.
I mark this topic as resolved/closed.
Again, thanks to fnostro !!!
I'm having a problem and I cannot understand why. I have a GridView and some other controls in an UpdatePanel. I'm trying to select a row by clicking anywere on it, so I'm using the following code to make the selection possible:
r.Attributes.Add("onclick","javascript:" + Page.ClientScript.GetPostBackEventReference(grdUtilizatori, "Select$" +r.RowIndex,true));
My problem is that the page is making full postback (the entire page is coming back from the server, not just the updatepanel).
If I'm using a simple Select command, the postback will be just partial. I compared the generated source for the page and the javascript looks identical.
Select
<tr onclick="javascript:__doPostBack('ctl00$CPH$grdUtilizatori','Select$0')">
Can you please tell me what am I doing wrong?
I found a solution on web, I've added to the update panel the following
<Triggers>
<asp:AsyncPostBackTrigger ControlID="grdUtilizatori"
EventName="SelectedIndexChanged" />
</Triggers>
I'm trying to speed up my Repeater so that not as much HTML has to be resent via the AJAX UpdatePanel on each call.
So here's what I have (a very much simplified version):
<asp:Repeater ID="rptContactSteps" runat="server">
<ItemTemplate>
<p>Script:<br /><%#mobjSDIT.FormatText(Eval("script"))%></p>
<p>Notes:<br /><%#mobjSDIT.FormatText(Eval("notes"))%></p>
<asp:UpdatePanel ID="upStep" runat="server" UpdateMode="Conditional">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="rptContactSteps" EventName="ItemCommand" />
</Triggers>
<ContentTemplate>
<p>Contact/Step Notes:<br /><%#mobjSDIT.FormatText(Eval("contact_step_notes"))%></p>
<asp:ImageButton ID="btnSaveAndCompleteLastStep" runat="server" ImageUrl="~/images/content/buttons/save-and-complete-button.png" CommandArgument='<%#Eval("step_contact_tie_id")%>' />
</ContentTemplate>
</asp:UpdatePanel>
</ItemTemplate>
</asp:Repeater>
So, when I click 'btnSaveAndCompleteLastStep' I want all the UpdatePanel in 'rptContactSteps' to update. Having the UpdatePanel inside the ItemTemplate should help prevent having to re-load the html/text that populates the Eval("script") & Eval("notes"), since the value of these variables could be very large and over a 3G connection this could be very costly (in time & money).
I though by adding the async trigger it'd work as I have used this type of trigger before, but not when inside the Repeater. Currently the UpdatePanels aren't getting updated at all, except from the one from which the button was pressed.
Any ideas anyone?
They aren't getting updated except by the one that is called because the update mode is set to conditional, and by default the ChildrenAsTriggers is set to true. So if you want them all to update when one of them is changed, then you will need to find each of the update panels in each of the repeater items and call .Update() on the update panel, or you can change the update mode to "Always", or just wrap your repeater in an update panel instead of wrapping just the items.
Does that make sense? If not I can expand.
That behavior sounds ok to me because postback from within an updatepanel will not update anything outside of it by default.
One way you can try is on your btnSaveAndCompleteLastStep click , find each updatepanel in the repeater items and call Update() on it.
I am completely stumped on this and would really appreciate any help.
I am working on a user control that is situated inside of an update panel. There is a button on the form which loads some data. This is working correctly.
There is also a drop-down box to filter the data. Changing this does initiate a post back, however nothing happens. The drop-down box goes back to it's default value the OnSelectedIndexChanged function is never called.
I've put break points in page_prerender and page_preload and both are being hit the post back is definitely occuring. Breakpoints withing the dropdownGroup_changed function are never hit.
Removing the update panel solves the problem, however it breaks the rest of the page so I can't use that for anything other than testing.
I've also verified that there is nothing in my prerender / page load that is resetting the page's state.
Here is the update panel code:
<asp:UpdatePanel ID="UpdatePanel6" runat="server" ChildrenAsTriggers="true" UpdateMode="Conditional" >
<ContentTemplate>
<ucControlName:ControlName ID="ControlName1" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
Here is the drop-down in question - It is located inside of the user control
<asp:DropDownList ID="dropdownGroup" runat="server" Visible="false" AutoPostBack="true" OnSelectedIndexChanged="dropdownGroup_changed"></asp:DropDownList>
It is of course visible and databound by the point in the code where the issue is occuring
A bit more info-
added Both a hard coded dropdown (To rule out a stupid databinding issue) and a textbox to the same control. I have the same issue.
It appears that the event isn't triggering because the values are never changing as far as .net is concerned. I've checked the control during page_init and page_load - the value is always the same.
The fact that the button works but the other controls don't makes me think that there is a view state issue here somewhere but I can't quite ferret out what is causing it. Viewstate is enabled for the page and the panel- don't know if anything else could be overriding / corrupting it.
Did i mention that I hate update panels with a passion? because I hate update panels with a passion.
I suggest checking the 'Value' property for each 'ListItem' in the 'DropDownList' control. If they are all the same even if the 'Text' properties are different, then the 'OnSelectedIndexChanged' will not fire at all since ASP.NET cannot tell if anything has changed (See this related question for more info.)
This was the real cause of my problem even though I, too, had a 'UserControl' with a 'DropDownList' inside an 'UpdatePanel' and the 'AutoPostBack' was firing as expected. I thought the UpdatePanel was the culprit but it was not the case. Each of the items in my DropDownList had the same underlying value of "10" even though they had distinct 'Text' values. I changed them to each have a unique value which then allowed for the OnSelectedIndexChanged event to fire thus fixing the problem.
Two answers for the price of one:
Are you calling DataBind() in your Page_Load? If you do that on a PostBack, you will lose events. Replace the call with the following:
if (!IsPostBack) {
DataBind();
}
If your DropDownList is outside your UpdatePanel, you need to add a Trigger as follows:
<asp:UpdatePanel ID="UpdatePanel6" runat="server" ChildrenAsTriggers="true" UpdateMode="Conditional" >
<Triggers>
<asp:AsyncPostBackTrigger ControlID="dropdownGroup" EventName="SelectedIndexChanged" />
</Triggers>
<ContentTemplate>
<ucControlName:ControlName ID="ControlName1" runat="server" />
</ContentTemplate>
</asp:UpdatePanel>
Have you tried UpdatePanel.Update (); after your databind.
I have a tabpanel with a calendar control on the 4th tab but when I select a date, the postback causes the tabpanel to return to the first tab instead of the 4th that it came from.
Is there a way to get it to return to the tab that the calendar control is on and not revert back to the first tab ?
I know setting autoPostback to true on the TabContainer will do this but that means it reloads on every tab change not just the one I want.
Any ideas ?
Wrapping the contents of the fourth tab in an UpdatePanel control should do the trick.
<ajaxToolkit:TabPanel runat="server" ID="tabCS" HeaderText="Country Settings">
<ContentTemplate>
<asp:UpdatePanel runat="server" ID="upCountry" UpdateMode="Conditional">
<ContentTemplate>
... content and calendar
</ContentTemplate>
</asp:UpdatePanel>
</ContentTemplate>
</ajaxToolkit:TabPanel>
Here is a best practice that I've found.
Unless other tabs in the tab panel need to be updated only put the contents of each panel in an update panel. If you need to update other panels you can call the method programmatically to update them.
There are two good reasons for this:
1.) By putting update panels in the tabs you will have fewer bits to get back from the server.
2.) Calling the update methods programmatically makes you more aware of what it is you are providing the end user and you won't forget to update the data.
Remember that if you use multiple panels to change the update mode from always to conditional so that only the relevant information is updated on the client.
Also if you want to put the entire tab panel control into the update panel you may need to add any formatting that is done to a CSS file since my experience is that it fails to retain the default formatting with it updates.
If you need more info or a code sample just message me.
Andrew