Updating DOM elements with JQuery following partial postbacks from Update Panels in ASP.net webforms

While working on implementing some of functionality on my online favorites manager (www.linqto.me) which I encourage everyone to check out, I came across the following problem:


  • On one of the pages of the site, I needed the page to be able to handle partial postbacks and bring back information from the server side onto the HTML markup of the page asynchronously: this is easy enough to accomplish using an UpdatePanel
  • Once the content of the page was updated by the UpdatePanel, I needed some more control and further processing of the DOM: to achieve this, I would need a JavaScript function to fire following the update to the DOM performed by the UpdatePanel and make further changes to the DOM – this is a bit more challenging
  • Since I had to reuse this functionality in several places inside the website, I needed to package all of this inside a UserControl that would have the UpdatePanel, inject the script into the page, and register it to fire off the JavaScript function call after each partial postback was complete.

In this article, I will try and detail how such a setup can be achieved for maximum re-usability.



In order to explain how you could go about doing such a thing, I have created a simpler / stripped down example (although you can look into the bookmark import feature described here for www.linqto.me to see a more complex usage). The sample I will walk you through looks like the following screen-shot: it consists of two progress like bar indicators that will show a percentage of how much of a total value is used up – this can be business data, metrics, pressure, battery charge, anything else you want.



large?v=1.png

The bar indicators are actually composed of two divs each (one div – with a blue or pink color - inside another div with a gray background). When you start the example, the two gray indicator div elements which show the total capacity will only appear, since the width values of the interior div elements are 0 with by the styling of the page:



<style>
.grayDiv{
background-color: lightgray;
border: solid 1px;
border-color: gray;
width: 500px;
}

.blueDiv{
background-color: lightblue;
width: 0px;
}

</style>








Indicator 1:
<br />
<div id="bar1" class="grayDiv">
<div id="indicator1" class="blueDiv">&nbsp;</div>
</div>
<br />






Notice that the style element for the .blueDiv class attributes a width of 0px to the inner div, making it invisible.



When the ‘Update Indicators’ button is pressed, it will trigger a partial postback since it is contained inside the update panel. A portion of the markup is updated including the values of the two hidden fields which will contain the values retrieve from the server-side computation. Following the partial postback, the page would then call the JavaScript function to make changes to the width of the inner div elements and set a new width value in the CSS style and graphically display the data retrieved.



In the sample provided, the entire control is contained in .ASCX and ASCX.cs files that are named WebUserControl. If you look at the markup of the control, you will see that it makes use of an UpdatePanel server control that contains a LinkButton control (the ‘Update Indicators’ button) and two hidden fields:



<asp:UpdatePanel ID="updUpdateIndicators" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:HiddenField ID="valIndicator1" runat="server" ClientIDMode="Static" />
<asp:HiddenField ID="valIndicator2" runat="server" ClientIDMode="Static" />
<asp:LinkButton ID="lnkUpdateValues" runat="server" Text="Update Indicators" OnClick="lnkUpdateValues_Click" />
</ContentTemplate>
</asp:UpdatePanel>






When the button is clicked, the update panel initiates a partial postback to the server, where the code for the lnkUpdateValues_Click() event handler will run. Here is the code for the event handler in question:



//event handler for the link button click event
protected void lnkUpdateValues_Click(object sender, EventArgs e)
{
//create a couple of random numbers that vary between 0 and 500 and assign them to the hidden fields
Random randGenerator = new Random();
int val1 = randGenerator.Next(0, 500);
int val2 = randGenerator.Next(0, 500);

//assign these new values to the hidden fiels and send the entire thing back to the update panel
valIndicator1.Value = val1.ToString();
valIndicator2.Value = val2.ToString();
}






All the code does is that it calculates two random integer values that are between 0 and 500 and then sets the resulting numbers as the values of the two hidden fields valIndicator1 and valIndicator2.



However, please note that the div elements that are responsible for displaying the data in a more graphical format are not contained inside the update panel, and the markup resulting from the partial post-back will not change these elements.



Here is where the magic comes in. We need a JavaScript function to be registered so that is it fired whenever the update panel is updated. This function will then make further changes to the DOM (Document Object Model). The script needs to be dynamically injected the first time the control is rendered on the page it will live on. Subsequent postbacks or partial postbacks of the page to the server should not re-inject the script again. To achieve this, we use the Page_Load event handler for the control with the following code:



protected void Page_Load(object sender, EventArgs e)
{
//attempt to inject javascript into the loading page
ScriptManager.RegisterClientScriptInclude(
this, GetType(), "valuesJqScript", ResolveUrl("~/scripts/ValuesUpdater.js"));

ScriptManager.RegisterStartupScript(this.Page, GetType(), ClientID, "WireUpValues();", true);
}






This code is the interesting part: the first line, where we call the ScriptManager.RegisterClientScriptInclude method, will indicate to the page hosting the control that it should also load a JavaScript file that is located in the /scripts/ folder and that is called ValuesUpdater.js. This line of code will also append a script block to the page instructing the browser to also load the script alongside the rest of the resources that are used by this page.



The second line will call the ScriptManager.RegisterStartupScript overload method. This method will specify what the name of the JavaScript function to be called after each partial postback is: in our case the file called ValuesUpdater.js defines a function called WireUpValues, which should be called. Here is the code of the script function:



function WireUpValues() {

//each time the update panel reload the HTML markup, get a hold of the hidden controls
var val1Control = $("#valIndicator1").val();
var val2Control = $("#valIndicator2").val();

//select the two divs that are supposed to show the progress bars
var div1 = $("#indicator1");
var div2 = $("#indicator2");

//set the width css width values of the two divs to match the values passed in
div1.css("width", val1Control);
div2.css("width", val2Control);
}






What the code does is that it uses JQuery to select the two hidden fields from the HTML that is rendered by the User Control. These hidden fields are declared with a ClientIDMode property set to static, so their DOM ID elements will be set to fixed values, the same values that we will use in the JQuery selectors to select the controls. The hidden fields store the values of the server computed variables val1 and val2. The JavaScript function then selects the div elements we need to change the width for, using JQuery selectors, and will proceed to call the css() function on these JQuery wrapped objects to reset the width property to the values indicated by the hidden input controls.



There are two overloads of the RegisterStartupScript method geared at achieving one of the following actions:

  • The script is called once when the control is loaded, if this overload is used
  • The script is called when the control is loaded and each and every time there is a partial postback on the control, if this overload is called – which is the overload used in the sample project.

To wrap up, here is the workings of the project from A-Z now that we have looked at the code:

  1. The control gets loaded on the page and the Page_Load event handler of the UserControl is called.
  2. This instructs the page to include a JavaScript file which should be loaded with the page and will wire up the function to be called once the page has loaded and when a partial postback from the control has completed (the HTML markup from the postback is incorporated into the page).
  3. The function fires on the page load and on subsequent partial postbacks and executes a simple logic of transferring the values of two integers (expressed as hidden fields) into CSS classes that make the divs be wider or smaller.

You can download the sample from . Happy coding with ASP.net Webforms and JQuery.

Paul Cociuba
www.linqto.me/about/pcociuba

Continue reading...
 
Top Bottom