Search code examples
javascriptasp.netpostbackviewstate

ViewState lost between consecutive partial postbacks?


Background:

I have a page where I have various client-side events being handled with JavaScript. I want to "sync" some of these events with server-side events, or otherwise call functions from the code-behind.

Some of the functions I want to call with JavaScript may make changes to controls (e.g. changing a textbox value) in a form I have on the page. They may also change some values I have stored in the ViewState, as I want some values to persist through postbacks. I do not want to a full postback, and have the controls that may be changed in an update panel.

I am currently "calling" functions in my code-behind with JavaScript by clicking invisible buttons that trigger partial postback on my page through an asynchronous postback trigger in my update panel.

Problem:

One of my client-side events calls a JavaScript function that clicks more than one of the invisible buttons (client-side stuff happens between the clicks that may affect how the the code-behind functions behave). When I have the JavaScript clicking more than one button, the changes made to the ViewState do not seem to persist, and only the changes from the last click are observed.

Example:

I might not have explained this very well, so here is a simplified version of what I have (which I can reproduce the issue with).

Markup:

<asp:Button ID="btnA" runat="server" style="display: none;" />
<asp:Button ID="btnB" runat="server" style="display: none;" />
<div style="background: red; width: 100px; height: 100px;" onclick="AB();"></div>

<asp:ScriptManager ID="ScriptManager1" runat="server"></asp:ScriptManager>
<asp:UpdatePanel runat="server" ID="upForm" UpdateMode="Conditional">
    <Triggers>
            <asp:AsyncPostBackTrigger ControlID="btnA" EventName="Click" />
            <asp:AsyncPostBackTrigger ControlID="btnB" EventName="Click" />
    </Triggers>
    <ContentTemplate>
    </ContentTemplate>
</asp:UpdatePanel>

JavaScript:

function AB() {
    $('#<%= btnA.ClientID %>').click();
    $('#<%= btnB.ClientID %>').click();
}

Code-behind:

Protected Sub btnA_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnA.Click
    ViewState("AB") += "A"
End Sub
Protected Sub btnB_Click(ByVal sender As Object, ByVal e As EventArgs) Handles btnB.Click
    ViewState("AB") += "B"
End Sub

Questions:

  1. Why are the changes to ViewState between partial postbacks lost?
  2. How can I save the changes between the partial postbacks? Session variables work great, but I would rather not have to resort to using them. I also cannot save the values in an invisible control as I am actually changing a serialized object in the ViewState.
  3. Is there perhaps a better way I could be doing this that would work?

Solution

  • I've managed to get it working for my case, but I think some of the options other users have suggested could have worked for me as well. Since my case seems pretty unique (partly because it's a hack method), I've included some other suggestions in this answer for future reference.

    1. Since the JavaScript is simulating two buttons being clicked, two consecutive partial postbacks are made. The second request is fired before the first one is returned, and so the second server event grabs the old ViewState rather than the updated one from the first event.

    2. Since my client and server events did not have to be perfectly in sync (it only needs to appear in sync to the user), I reorganized the code behind functions so that only one partial postback was needed per client event, while still keeping the logical flow of events. To be clear, this is more a workaround than a real solution.

      • Crab Bucket suggested serializing a JSON object into a hidden form field. While not exactly what I'm looking for, I think it's worth mentioning in case others stumble across a similar issue. More details here.
    3. Daniel recommended using page methods, which I've taken a (brief) look at and it seems like it might work. To move away from update panels for me at this point and put the page back together again with his suggestions though would take quite a bit of work due to what's already on the page. I might come back to this in the future though and try it out (or maybe use it for something else). Some more details on using jQuery to call page methods and consume web services.