UpdatePanel and Rendered (Inline) Javascript

It seems that the UpdatePanel essentially replaces the InnerHTML of  a DIV with the delta returned from the server. If you try this yourself you will notice that any javascript elements in the html are not fired.

All javascript registered on the server-side (if you are using .NET) with the ScriptManager is put into a separate section of the returned delta. The atlas runtime obviously then loads these scripts into the document manually.

What if the returned HTML has Javascript tags already rendered in it? Nothing. :(
Such was our predicament and we had no control over the HTML that would be returned to the UpdatePanel (ReportViewer Control). Could we manually load the javascript ourselves when the UpdatePanel returns the payload? As it turns, we could.

You can create script elements on the fly and they get evaluated as you do. Atlas has the ScriptLoader object that will do it for you if your JavaScript is an external reference. Tweaking this idea we got a solution that found all the new Script elements and added them to the document.

The code is below; the scriptLoader was taken from this post.
The main thing to know is that a script element has a text property that can be modified.
The atlas scriptloader sets the src property whilst the innerHTML and innerText properties are readonly.

functionParseScript(control){
        if(!control){return;}
      
for(var n=0;n<control.children.length;n++){
            
if(control.children[n].tagName == ‘SCRIPT’){
                  
window.ScriptLoader.loadScript(control.children[n].innerHTML);
              }
else{
                  
ParseScript(control.children[n]);
             }
        }
}window.ScriptLoader =

new function(){varqueuedScripts = new Array();
varcurrentScript = null;functiononScriptLoaded(){
//Load next
doScriptLoad();
}

functiononScriptError(){
//Add Support for error handlers
//Load next
doScriptLoad();} functiononScriptReadyStateChange(){
    if(event.srcElement.readyState == “complete” ||event.srcElement.readyState == “loaded”)
        onScriptLoaded();
}
this.loadScript = function(scriptPath){
     queuedScripts.push(scriptPath);
     if(currentScript == null)
       doScriptLoad();
}
//Does the actual script loading
functiondoScriptLoad(){
if(currentScript){currentScript.onload = onScriptLoaded; //For Mozilla/Opera
currentScript.onerror = onScriptError; //For Mozilla/Opera
currentScript.onreadystatechange = onScriptReadyStateChange; //For IE

}if(queuedScripts.length == 0)
return;currentScript = document.createElement(“SCRIPT”);
currentScript.onload = onScriptLoaded; //For Mozilla/Opera
currentScript.onerror = onScriptError; //For Mozilla/Opera
currentScript.onreadystatechange = onScriptReadyStateChange; //For IE

currentScript.type = “text/javascript”;
currentScript.text = queuedScripts.pop();
document.getElementsByTagName(‘head’)[0].appendChild(currentScript);
}}

Edit:
In order to call ParseScript after an Asych postback we do the following. Now this was written when Ajax ASP.NET was stilled called Atlas so there is probably a better way these days, but it works for us ;)


function EndRequestHandler(sender, args)
{
   ParseScript($get('ContainerControlID'));
}

Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);

About these ads
Tagged , , ,

9 thoughts on “UpdatePanel and Rendered (Inline) Javascript

  1. ZZ says:

    What would call the ParrseScript method on the client though? (and when?) What if some control nested inside the update panel is what triggered the asynchronous postback?

  2. adammills says:

    I have edited the post to show how we do it. This solution was for a legacy custom control we could not modify. The page is focused around this control so every asych postback we want to run all inline scripts in the controls container (DIV).

    How you call ParseScript would depend on what you are trying to acheive. Generally you can modify custom controls to play nice with Ajax. If you can’t and our approach doesn’t work for you it’s possible to control when and where ParseScript runs from the server side.
    I.e. on postback test for asych, test the trigger control and add a javascript call to ParseScript if needed.

  3. Stephanie says:

    Thanks! this is just what I was looking for…for hours. Great Job!

  4. Thiago says:

    Thanks
    this post helped me a lot
    I was trying to bind a handler to “readystatechange” with jQuery, but it doesn’t seem to work as I expected. you just saved me

  5. thank this thread helped me alot

  6. sash says:

    This is one of those things that make you jump with joy. Some guy built a rich page that uses a number of third party controls and now they ask us to make “partial postback” work on it – just like that. We managed to but the 3rd party control was spitting javascript that we had no way of adding to the page directly – until i saw this page. Great job and a big thank u.

  7. adammills says:

    I’m glad it helped.
    I am also stunned that 4 years later it is still relevant!

  8. uovidelu says:

    Hey, thank you for the post. I’m a begginer, so can you please tell me where should I copy this part:
    function EndRequestHandler(sender, args)
    {
    ParseScript($get(‘ContainerControlID’));
    }

    Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);
    Thanks for your time

  9. abc says:

    abbey koi to help kar do

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 28 other followers

%d bloggers like this: