Solved

I need help dealing with a postback issue on a button click event in my ASP.Net app

Posted on 2009-06-30
20
491 Views
Last Modified: 2012-05-07
Hi experts,
I have an ASP.net application with VB.Net codebehind.  In my app I use HTML radiobuttons in my GridView's TemplateField, and also a button control on the form.  Users can click on a radiobutton to select a row from my GridView.  Once the user has selected a row the user clicks on the button and the value in my GridView's Amount Column is placed in a variable to perform a calculation.   This works fine but on the postback my radio button gets deselected.  What can I do to keep my radio button from deselecting?  I have posted my code in this post.


Thanks in advance,
mrotor
HTML SOURCE CODE:
 

 <asp:TemplateField>

          <ItemTemplate>

                 <input id="Radio1" type="radio" name="myRadio"  value="<%#Eval("Amount")%>"/>

           </ItemTemplate>

</asp:TemplateField>
 

VB.NET Codebehind:
 

Protected Sub Button1_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles Button1.Click

        Dim dblCost As Double = 0

       Dim dblTotal as Double = 0
 

       dblCost = CDbl(Request.Form("myRadio"))

       dblTotal = dblCost * .15 

      lblTotal.Text = dblTotal.ToString

End Sub

Open in new window

0
Comment
Question by:mainrotor
  • 12
  • 7
20 Comments
 
LVL 20

Expert Comment

by:ddayx10
ID: 24750431
One simple solution is to add viewstate to your input element.

<input id="Radio1" type="radio" name="myRadio"  value="<%#Eval("Amount")%>" runat="server" enableviewstate="true" />

Luckily I built a sample of your project yesterday so I was able to test it and it works fine.

:)
0
 

Author Comment

by:mainrotor
ID: 24750636
ddayx10
Thanks for the quick reply.  I added your code but it still didn't work.  The radio button still gets deselected.  Do I also have to make changes to my button control?

Thanks
mrotor
0
 
LVL 15

Expert Comment

by:Solar_Flare
ID: 24750674
Because your radio buttons are simply html controls, their state is not maintained and will be lost on postback.

I think the easiest way to deal with this is to add some javascript to your page that goes and selects the right radiobutton based on the last posted back value. Adding the following code to your Button1_Click should do it


C#
 

ClientScript.RegisterStartupScript(this.GetType(), "RadioSelect", "var radios = document.getElementsByName('myRadio'); " + 

                                "var radioLength = radios.length; " +

                                "for(var i = 0; i < radioLength; i++) {" +

                        	"radios[i].checked = false;" +

		                "if(radios[i].value == '" + Request.Form["myRadio"] + "') " + 

			        "radios[i].checked = true;" +

		                "}", true);
 

VB.Net
 

ClientScript.RegisterStartupScript(Me.GetType(), "RadioSelect", "var radios = document.getElementsByName('myRadio'); " & _

                                "var radioLength = radios.length; " & _

                                "for(var i = 0; i < radioLength; i++) {" & _

                                "radios[i].checked = false;" & _

                                "if(radios[i].value == '" + Request.Form("myRadio") + "') " & _

                                "radios[i].checked = true;" & _

                                "}", True)

Open in new window

0
 

Author Comment

by:mainrotor
ID: 24750807
Solar flare,
Thank you for your response.  Your solution almost works.  After I click my button control it always has the bottom (i.e. last) radio button selected, not the radio button that was selected prior to the button click event.  What could be causing this?

mrotor
0
 
LVL 20

Expert Comment

by:ddayx10
ID: 24750928
Dude that works. The only reason it wouldn't work is the likely culprit, you are rebinding to the gridview on your postback. The JavaScript solution can be made to work, but you will have to track the radiobuttons more carefully because after you rebind if the data that comes back is different, or lays out differently it will fail the way it is written. This will require a bit more complicated script than that.

I think I would adjust my thinking a bit. Add a column in your db for selected. Update the db after posting back, but before you re-bind**. Then set whether the input is selected or not during the row_databound process.

**Various ways you could update your data (AJAX, loop through the gridview pulling out the control and evaluating it's state), etc.

Maybe there's something I'm not seeing here. I gotta go for tonight anyway... good luck.
0
 
LVL 20

Expert Comment

by:ddayx10
ID: 24750951
If you still don't have this figured out I'll take a look at it again tommorrow and see what can be done.
0
 
LVL 20

Expert Comment

by:ddayx10
ID: 24752185
Ok so it's tommorrow somewhere...

I haven't seen a reply from you on your thoughts so I will start here:

After thinking about it, and re-checking, and looking at your code the first and easiest solution that comes to mind goes like this.

It looks like the button_click event is what you are using to cause the postback (since that's what you showed for the sample code).

I don't see any databinding happening there. Although I am convinced that databinding is the only thing that would stop viewstate from working for you here. That means the databinding is probably happening in the page_load (which always fires before the button_click event). You likely don't need to be re-binding the data every time you post back, and in this case it is killing you. It is very common to setup databinding in a subroutine and call that in page_load, but not every time. Only call it when you need to (like after an update/insert/delete etc).

So:

1) enable viewstate on your radiobutton
2) restrict your databinding in the page_load event
EX.
If not IsPostBack Then
   bindToGrid()
End If

If you require rebinding of the data every time you postback then you have a bit of work to do. If you do not require databinding on each postback (most applications dont) then this will fix you up.
0
 

Author Comment

by:mainrotor
ID: 24759160
ddayx10,
Thanks for your suggestions.  I will try them and post my results tomorrow.

mrotor
0
 

Author Comment

by:mainrotor
ID: 24759214
ddayx10,
on a previous response you mentioned you had built a sample of my project.  Maybe you can post the code so i can compare it to my code.  I'm including some code that shows how I'm binding my gridview.  I don't think I am doing anything that would cause the radiobuttons to be deselected.

Thanks,
mrotor
        Dim dtX As New DataTable()

        dtX.Columns.Add("Code")

        dtX.Columns.Add("Name")

        dtX.Columns.Add("Amount")

        GridViewPup.DataSource = Nothing
 

        For intRow = 0 To x

            row = tableX.NewRow()

            row("Code") = PUList(intRow).AgentCode.ToString

            row("Name") = PUList(intRow).AgentName.ToString

            Dim dblAmountPU As Double = PUList(intRow).AgentRate.ToString

            row("Amount") = dblAmountPU.ToString("N2")

            tableX.Rows.Add(row)

        Next
 

        Dim columnX As DataColumn

        For Each columnX In tableX.Columns

            Console.WriteLine(columnX.ColumnName)

        Next
 

        GridViewPup.DataSource = tableX

        GridViewPup.DataBind()

Open in new window

0
 
LVL 20

Expert Comment

by:ddayx10
ID: 24759516
The sample I built is over there in your last post :)
http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/Q_24530824.html

But I see you are building in VB so I'll update it for ya and post below.

I appreciate you posting the above code sample, but I don't know what context that runs in (page_load, subroutine, subroutine called from page_load)...

The key in your sample code that I'm trying to point out is here:
        GridViewPup.DataSource = tableX
        GridViewPup.DataBind()

Lets say that is running in page load (my personal guess). Now you call your click your button and call your button event after some radio buttons have been selected. The 1st thing that happens is page_load fires. The gridview is rebound. All items in the gridview are re-created. 2nd your button_click event fires and does what it does. Now the page is loaded back up. It remembers nothing about your previous gridview in viewstate because it was destroyed and rebuilt from scratch. When it was destroyed and re-built from scratch if any data changed, then it may build in a slightly different way and this is going to make tracking it with JavaScript a difficult task at best.

So in the sample note in the page_load I've built is so you can bind on every postback or you can switch it around and bind only once. If you toggle between these you will see that even though you used the button to cause the postback in one situation the radio buttons remember their previous state and in the other situation they dont.

You can use either the button or the dropdownlist to cause a postback for testing.
****SAMPLE ASPX*****

****I added some stuff when I was answering other questions,****

****but it doesnt affect what we are talking about****

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 

<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">

    <title>MainRotor Sample</title>

	<script type="text/javascript">

	function unClear(rbElem)

	{

		var lbl1 = document.getElementById('lbl1');

		lbl1.innerHTML = rbElem.value;

	}
 

	</script>

	<style type="text/css">

		.rowClass:hover{background:#c0c0c0;}

	</style>

</head>

<body>

    <form id="form1" runat="server">

	<asp:GridView ID="GridView1" runat="server" 

		EditRowStyle-CssClass="rowClass" 

		RowStyle-CssClass="rowClass" 

		AlternatingRowStyle-CssClass="rowClass" 

		SelectedRowStyle-CssClass="rowClass">

		<Columns>

			<asp:TemplateField>

			<HeaderTemplate>Header Here</HeaderTemplate>

				<ItemTemplate>

					<div>

					<input id="Radio1" type="radio" onclick="unClear(this);"

						value=<%# Container.DataItem %> runat="server" enableviewstate="true" />

						

					<asp:DropDownList ID="ddl1" runat="server" AutoPostBack="true">

						<asp:ListItem Text="aa" Value="aa"></asp:ListItem>

						<asp:ListItem Text="bb" Value="bb"></asp:ListItem>

					</asp:DropDownList>

					</div>

				</ItemTemplate>

			</asp:TemplateField>

		</Columns>

	</asp:GridView>

	

	<span>Label1</span><asp:Label ID="lbl1" runat="server" />

	<asp:Button ID="btn1" runat="server" Text="ClickMe" />

    </form>

</body>

</html>
 
 
 

****CODE BEHIND****

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        'Comment out option 1 or option 2 to see the effects they create
 

        'Option 1

        If Not IsPostBack Then

            bindGrid()

        End If
 

        'Option 2 (not usually a good idea)

        'bindGrid()
 

    End Sub
 

    Private Sub bindGrid()

        Dim dataSource As New List(Of String)

        dataSource.Add("Item1")

        dataSource.Add("Item2")

        dataSource.Add("Item3")

        dataSource.Add("Item4")

        GridView1.DataSource = dataSource

        GridView1.DataBind()
 

    End Sub

Open in new window

0
Do You Know the 4 Main Threat Actor Types?

Do you know the main threat actor types? Most attackers fall into one of four categories, each with their own favored tactics, techniques, and procedures.

 

Author Comment

by:mainrotor
ID: 24766153
ddayx10-
Thanks for posting your code.  After comparing your code with mine, I figured out why my radiobuttons were being deselected after a button click event. In the Radio control this works:   value=<%# Container.DataItem %>
This doesn't work:   value="<%#Eval("Amount")%>"

but replacing my code with your code causes my buttons not to be grouped (i.e. I can select multiple radio buttons), even if I add the name="PickUpX" attribute.  Why??????  This is killing me.  Please help.

YOUR CODE:
<input id="Radio1" type="radio" name="PickUpX" value=<%# Container.DataItem %> runat="server" enableviewstate="true" />

MY CODE:
<input id="Radio1" type="radio" name="PickUpX" value="<%#Eval("Amount")%>"  runat="server" enableviewstate ="true"  />

Thanks in advance,
Ricardo Rubio
0
 
LVL 20

Accepted Solution

by:
ddayx10 earned 500 total points
ID: 24770874
OK well...<insert liberal amounts of intolerant language here>!

I used <%# Container.DataItem %> because of the type of datasource I was using (list(Of String))

That won't work with a sqldatasource it will return the following in html output:
<input type="radio" value=System.Data.Common.DataRecordInternal ...etc>

When using a sql as datasource then any of the following will produce the same result:
(Insert your own column name)
<input id="Radio1" type="radio" value=<%# DataBinder.Eval(Container.DataItem,"testID") %> />
<input id="Radio2" type="radio" value=<%# Container.DataItem %> />
<input id="Radio3" type="radio" value=<%# Eval("testID") %> />

I don't see what that has to do with the grouping of your radio buttons though! If I re-read your last post it seems like you may be getting confused by something else (which I didn't think of before now). No matter what you make the value that is not going to effect the groups, but the name does (as you indicated you are likely aware of this. I'm just trying to point out that it's not the value assignment or lack thereof that is causing your grouping to fail...use what you started with there.

What is causing your grouping to fail is adding [runat="server"] to you inputs :(

I didn't think of it because it doesn't make a lot of sense, but I learned something new. Brief side-trip here. The second we turn those inputs into server controls they begin falling into the INamingContainer interface. What this is for is to make sure that all the controls with ID's in a gridview (in this example) are given unique ID's so that the page renders correctly. Now the "name" attribute does not have to be unique in HTML and so it shouldn't be affected by the INamingContainer convention, but it is <insert more swearing here>...

To just get to the point. When we add run="server" to the inputs they are each given unique names and that breaks the grouping. All you have to do is view the source with the runat="server" on and off to see the difference and why this is not working out.

Well that pretty much completely blows my theory of using viewstate out of the water here! I have tried many things:

1) Leave the inputs as server controls and use JavaScript to re-assign all the names after the page renders... that works for the grouping, but it completely destroys the viewstate and therefore makes it a wash.

2) Try to intercept the controls as they are being created in the Row_Created Event and re-assign the name attribute...short story doesn't work (although it was fun tryin).

3) Variations on theme 2.

So it would be easy to say...you are scr**wed here, but that's not helpful :)

We have 2 choices:

Choice A: (this is my choice)
Make the inputs server controls with viewstate and use javascript to manage grouping. Basically force them all in the same group even though they are not.

Choice B:
Make the inputs html controls only, give them their name for grouping, and track which one's are selected, trying to match them back up after postback.
NOTE: This has the disadvantage of being a problem if the data changes after postback (unflexible). Plus it's just dumb!

So! I've updated my sample for you to not only use sql as the datasource, but to incorporate OPTION A. Works like a charm over here...hope you find it does the same for you.

PS: Still can't databind on every postback or the viewstate breaks.
****ASPX CODE****

<%@ Page Language="VB" AutoEventWireup="false" CodeFile="Default27.aspx.vb" Inherits="Default27" %>
 

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 

<html xmlns="http://www.w3.org/1999/xhtml">

<head runat="server">

    <title>MainRotor Sample</title>

    <script type="text/javascript">

		

		function manageGrouping(valueSelected)

		{

			var radios = document.getElementsByTagName('input');

			

			for(i=0;i<radios.length;i++)

			{

				if(radios[i].type == 'radio')

				{

					if(radios[i].value == valueSelected)

					{ radios[i].checked = true; }

					else

					{ radios[i].checked = false; }

				}

			}

		}

    

	</script>

</head>

<body>

    <form id="form1" runat="server">

	<asp:GridView ID="gv" runat="server">

		<Columns>

			<asp:TemplateField>

			<HeaderTemplate>Header Here</HeaderTemplate>

				<ItemTemplate>

					<input id="Radio3" type="radio" name="groupX" value=<%# Eval("testID") %> runat="server" enableviewstate="true" onclick="manageGrouping(this.value);" />

				</ItemTemplate>

			</asp:TemplateField>

		</Columns>

	</asp:GridView>

	<asp:Button ID="btn1" runat="server" Text="ClickMe" />

    </form>
 

</body>

</html>
 
 

****CODE BEHIND****
 

Imports System.Data.SqlClient
 

Partial Class Default27

    Inherits System.Web.UI.Page
 

    Private ReadOnly Property connStr() As String

        Get

            Return ConfigurationManager.ConnectionStrings("conn").ToString()

        End Get

    End Property
 

    Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load

        If Not IsPostBack Then

            bindGrid()

        End If

    End Sub
 

    Private Sub bindGrid()

        Dim conn As New SqlConnection(connStr)

        Dim cmd As New SqlCommand("SELECT * FROM DevTable", conn)

        conn.Open()

        Dim dr As SqlDataReader = cmd.ExecuteReader

        gv.DataSource = dr

        gv.DataBind()

        dr.Close()

        conn.Close()

        conn.Dispose()

    End Sub
 

End Class

Open in new window

0
 
LVL 20

Expert Comment

by:ddayx10
ID: 24770891
I typo'd this part:

***
When using a sql as datasource then any of the following will produce the same result:
(Insert your own column name)
<input id="Radio1" type="radio" value=<%# DataBinder.Eval(Container.DataItem,"testID") %> />
<input id="Radio2" type="radio" value=<%# Container.DataItem %> />
<input id="Radio3" type="radio" value=<%# Eval("testID") %> />
***

Should have been:
value=<%# Container.DataItem("testID") %> as the 2nd choice in that list.

So much for proof-reading before I submit :)
0
 
LVL 20

Expert Comment

by:ddayx10
ID: 24771412
Last thing...gone for long weekend so I'm not abandoning you I'm just having more fun than this till next Tues!
0
 

Author Comment

by:mainrotor
ID: 24832680
Hi ddayx10,
Sorry it's taken me so long to reply to your posts, but a few people in my department have been on vacation an I've had to cover for them. Anyhow, I finally got a chance to try your code.
Your code works in the sense that the radio button doesn't deselect on a post back. The problem now is that the value in the gridview's 'Amount' column for the selected row doesn't evaluate to anything. The thing that is causing the are the double quotes (" ") around the value attribute. For example:

USING YOUR CODE (keeps radiobutton selected but the 'Amount' column doesn't evaluate to anything):

<input id="Radio1" type="radio" name="PickUpX" value=<%# Eval("Amount") %>  runat="server" enableviewstate ="true"  onclick="manageGrouping(this.value);" />

USING MY CODE (Doesn't keep radiobutton selected but the value in the 'Amount' column is grabbed):

<input id="Radio1" type="radio" name="PickUpX" value="<%#Eval("Amount")%>"  runat="server" enableviewstate ="true"  onclick="manageGrouping(this.value);" />

Once again, notice the difference in the use of the double quotes in the VALUE attribute.  Why would that affect this.

View the code snippet to see how I get the value in the 'Amount' column.

Thanks ddayx10 for all your help it is really appreciated.  What is causing this?

mrotor :-)







Dim dblPU as Double = 0

Dim dblTotal as Double = 0

dblPU = CDbl(Request.Form("PickUpX"))
 

dblTotal = dblPU * 1.35

Open in new window

0
 
LVL 20

Expert Comment

by:ddayx10
ID: 24846300
...pretty confused over here!

I have the gridview databound to a sqldatareader. The table I am pulling from has a column named [amount]. Both of these fill the inputs value field identically for me:
value=<%# Eval("Amount") %>
value="<%#Eval("Amount")%>"

I don't think we are doing apples to apples here, and the difference is why you are getting a value with one and not the other although I don't know why.

0
 
LVL 20

Expert Comment

by:ddayx10
ID: 24846527
...ah I hate that I accidentally pressed ENTER and it posted (sorry).
<<--Continued from above>>
The code you posted for the origin of "Amount":
******************************
Dim dblPU as Double = 0
Dim dblTotal as Double = 0
dblPU = CDbl(Request.Form("PickUpX"))
dblTotal = dblPU * 1.35
******************************

I'm having a real hard time putting that into meaningful context... when I try that code:
Dim dblPU As Double = 0
dblPU = CDbl(Request.Form("groupX")) 'mines groupX yours is PickUpX (same diff)

I always get 0 because Request.Form("groupX") evaluated to nothing. It isn't there.

So what do you mean by "the value in the amount column is grabbed" using your code? Are you saying that the gridview is not binding anything to the value of the input (radiobutton)? Are you saying that you manipulate something else with that value, and you can't get a value out of it anymore with that code sample? It seems like you might be saying that you have an OnSelectedIndexChanged server side event that is being detrimentally affected somehow?

In all of these scenarios I would think you need to be getting at the value differently than you are, but without the context of that code sample I can't advise. Show me if you can, try to explain more too.

I can tell you that when binding a gridview to table data that those eval statements work in a variety of ways I have tried. When you use your binding method, the JavaScript I wrote should always work, the only reason it wouldn't is if there is not a good value being attached so I am suspicious of what is happening when you bind it with your syntax. Run it with your syntax and take a look at the view source from the browser...see what the control looks like there (post it if you can).

I'll keep trying to help, but I think we have to re-connect on communication at this stage.



0
 

Author Closing Comment

by:mainrotor
ID: 31598532
ddayx10 thank you for hanging tough with me.  You are an excellent programmer.
0
 
LVL 20

Expert Comment

by:ddayx10
ID: 24846610
Your kind comments brought me back, and after looking at the code again I'm guessing that when you bind amount to the radiobutton that it is not a unique value...in other words in value=amount sometimes you have the same value for multiple radiobuttons....this would break my JavaScript code. If that turns out to be the case though I can probably fix it :)


<input id="Radio3" type="radio" name="groupX" value="<%#Eval("Amount")%>" runat="server" enableviewstate="true" onclick="manageGrouping(this);" />


function manageGrouping(elementSelected)
{
      var radios = document.getElementsByTagName('input');
      
      for(i=0;i<radios.length;i++)
      {
            if(radios[i].type == 'radio')
            {
                  if(radios[i] == elementSelected)
                  { radios[i].checked = true; }
                  else
                  { radios[i].checked = false; }
            }
      }
}
0
 
LVL 20

Expert Comment

by:ddayx10
ID: 24865834
Ok I think I see you have moved on:

http://www.experts-exchange.com/Programming/Languages/Scripting/JavaScript/Q__24570729.html

You are using the old javascript in that new thread...might want to change to the new JavaScript I posted just above...

I'll leave ya to it through...fresh ideas are good. I wish you had given me as much of your code to see in this thread as you did in the new one though...would have made it easier.
0

Featured Post

What Is Threat Intelligence?

Threat intelligence is often discussed, but rarely understood. Starting with a precise definition, along with clear business goals, is essential.

Join & Write a Comment

Enums (shorthand for ‘enumerations’) are not often used by programmers but they can be quite valuable when they are.  What are they? An Enum is just a type of variable like a string or an Integer, but in this case one that you create that contains…
JavaScript can be used in a browser to change parts of a webpage dynamically. It begins with the following pattern: If condition W is true, do thing X to target Y after event Z. Below are some tips and tricks to help you get started with JavaScript …
Get people started with the process of using Access VBA to control Outlook using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Microsoft Outlook. Using automation, an Access applic…
Get people started with the process of using Access VBA to control Excel using automation, Microsoft Access can control other applications. An example is the ability to programmatically talk to Excel. Using automation, an Access application can laun…

747 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

13 Experts available now in Live!

Get 1:1 Help Now