Click here to Skip to main content
Click here to Skip to main content

Persist JavaScript changes on postback

By , 6 Jun 2013
Rate this:
Please Sign up or sign in to vote.

The Problem

I have been developing a simple XML-based message board (I'll write an article on that when the project is done.) I wanted to let forum users select an image to serve as their avatar on the boards, but having to reload the page every time the user selected an image was a pain: the reload time was noticeable, and each postback created a history entry that was annoying. The obvious answer was to use JavaScript to update the user's image; that worked fine. Unfortunately, changing the src attribute of the generated img did not persist when I did want a postback to save the information.

The Solution

First off, here is my original HTML:

<table>
  <tr>
    <td rowspan='2'><asp:Image ID="UserAvatar" runat="server" /></td>
    <th><asp:Literal ID="UserName" runat="server" /></th>
  </tr>
  <tr>
    <td>Click on an image below to change your avatar.</td>
  </tr>
  <tr>
    <td></td>
    <td><asp:Button ID="SaveButton" runat="server" Text="Save" OnClick="SaveButton_Click" /></td>
  </tr>
  <tr>
    <td colspan='2'><asp:Literal ID="ConfirmationText" runat="server" Visible="false" 
      Text="Your choice has been saved." /></td>
  </tr>
</table>

Pretty straightforward. The second row has only a single cell, as the cell containing UserAvatar stretches down to fill the first cell position thanks to the rowspan attribute.

The solution I found starts with adding a hidden input field somewhere on the form; I put this underneath the code for my table:

<input type="hidden" id="persistAvatar" value="*" runat="server" />

Note the use of the runat attribute. This is important. Just as an ASP control gets rendered as vanilla HTML, you can effectively turn vanilla HTML into an ASP control by using this attribute: it instructs the compiler to allocate space in the view state and allow it to be accessed in code-behind. I think this is functionally equivalent to using a asp:HiddenField control, but I haven't tested it. The default value is so that I can test if the field has been used or not.

The next step was to add the JavaScript that would update the UserAvatar image:

function setAvatar(e) {
  var img = document.getElementById('ctl00_ContentHolder_UserAvatar');
  var hold = document.getElementById('ctl00_ContentHolder_persistAvatar')
  img.src = e.getAttribute('src'); ;
  hold.value = e.getAttribute('src');
  return true;
}

Note that, because of the runat, the id for persistAvatar is mangled with the master page, exactly as if it were an ASP control. e is the image that the user clicked. The src of UserAvatar  and the value of persistAvatar are set to the source of the clicked image. The available images are arranged in a table on the page; a typical image looks like this:

<img src='myserver/images/avatar/angry_baby.jpg' alt='' onclick='setAvatar(this);' />

So now, all of the pieces are in place: the user clicks an image, the selected image appears in the form, and the name of the file is saved to a hidden field, all without a postback.

One other piece of infrastructure needs to be added, to make sure that the avatar image is loaded properly out of the view state. In the page's Load event, I have this code:

If IsPostBack AndAlso persistAvatar.Value <> "*" Then            
    UserAvatar.ImageUrl = persistAvatar.Value
Else
    UserAvatar.ImageUrl = String.Format("/images/avatar/{0}", MyUser.ForumAvatar)
End If

When the page is first loaded, or on postback if the user made no change to the avatar image, UserAvatar is set to show image that already exists in the data store. If the user has clicked something else, then UserAvatar is set to the src of the selected image, which had been saved in persistAvatar. When the page is delivered to the user, the displayed image will be correct.

And so we come to the last bit, when the user actually clicks on the Save button and a postback occurs. Simplicity in itself:

Protected Sub SaveButton_Click(ByVal sender As Object, ByVal e As System.EventArgs)
    Dim U As User = Access.GetUser(MyUser.UserId)
    U.ForumAvatar = System.IO.Path.GetFileName(UserAvatar.ImageUrl)
    ConfirmationText.Visible = Access.UpdateUser(U)
End Sub

I retrieve the currently stored data for the web user, parse out the name of the designated image file, save it to the data structure, and update the data store.

Moving On

It was a bit of a challenge finding out how to do this, as it's not exactly intuitive. But once I found some examples (and many thanks to Tadit Dash for pointing me in the right direction) I realized that it is pretty simple. This technique should be easily extensible, with a hidden field for each piece of data that you need to persist.

If you have anything to add, let me know in the comments. And as always, if you found this useful, please vote up.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Gregory.Gadow
Software Developer (Senior)
United States United States
Gregory Gadow lives in Seattle, Washington and has been writing code for almost 25 years in more than a dozen programming languages. He works for a mid-size brokerage firm and holds the Series 7 and Series 66 brokerage licenses, but much prefers working as the company's programming department doing VB6, VB.Net, ASP, HTML, XML and SQL.

Comments and Discussions

 
GeneralMy vote of 5 PinprofessionalMihai MOGA13-Jul-13 20:51 
QuestionIt's kind of ironic PinmemberMember 90401376-Jun-13 5:33 
AnswerRe: It's kind of ironic PinmemberGregory.Gadow6-Jun-13 7:59 
GeneralMy vote of 5 PinmemberHaBiX5-Jun-13 19:57 
GeneralRe: My vote of 5 PinmemberGregory.Gadow6-Jun-13 3:31 
GeneralMy vote of 5 PinprofessionalTadit Dash5-Jun-13 6:09 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Mobile
Web01 | 2.8.140415.2 | Last Updated 6 Jun 2013
Article Copyright 2013 by Gregory.Gadow
Everything else Copyright © CodeProject, 1999-2014
Terms of Use
Layout: fixed | fluid