views:

16058

answers:

11

Hello,

I am having what I believe should be a fairly simple problem, but for the life of me I cannot see my problem. The problem is related to ScriptManager.RegisterStartupScript, something I have used many times before.

The scenario I have is that I have a custom web control that has been inserted into a page. The control (and one or two others) are nested inside an UpdatePanel. They are inserted onto the page onto a PlaceHolder:

<asp:UpdatePanel ID="pnlAjax" runat="server">
  <ContentTemplate>
    <asp:PlaceHolder ID="placeholder" runat="server">
    </asp:PlaceHolder>
    ...

protected override void OnInit(EventArgs e){
  placeholder.Controls.Add(Factory.CreateControl());
  base.OnInit(e);
}

This is the only update panel on the page.

The control requires some initial javascript be run for it to work correctly. The control calls:

ScriptManager.RegisterStartupScript(this, GetType(), 
                                    Guid.NewGuid().ToString(), script, true);

and I have also tried:

ScriptManager.RegisterStartupScript(Page, Page.GetType(), 
                                    Guid.NewGuid().ToString(), script, true);

The problem is that the script runs correctly when the page is first displayed, but does not re-run after a partial postback. I have tried the following:

  1. Calling RegisterStartupScript from CreateChildControls
  2. Calling RegisterStartupScript from OnLoad / OnPreRender
  3. Using different combinations of parameters for the first two parameters (in the example above the Control is Page and Type is GetType(), but I have tried using the control itself, etc).
  4. I have tried using persistent and new ids (not that I believe this should have a major impact either way).
  5. I have used a few breakpoints and so have verified that the Register line is being called correctly.

The only thing I have not tried is using the UpdatePanel itself as the Control and Type, as I do not believe the control should be aware of the update panel (and in any case there does not seem to be a good way of getting the update panel?).

Can anyone see what I might be doing wrong in the above?

Thanks :)

+4  A: 

When you call ScriptManager.RegisterStartupScript, the "Control" parameter must be a control that is within an UpdatePanel that will be updated. You need to change it to:

ScriptManager.RegisterStartupScript(this, this.GetType(), Guid.NewGuid().ToString(), script, true);
Keltex
Yes - I have tried using the control itself, which is nested within the UpdatePanel. The control is inserted into the placeholder, but I believe this should be ok?
Chris
A: 

Well, to answer the query above - it does appear as if the placeholder somehow messes up the ScriptManager.RegisterStartupScript.

When I pull the control out of the placeholder and code it directly onto the page the Register script works correctly (I am also using the control itself as a parameter).


ScriptManager.RegisterStartupScript(this, GetType(), Guid.NewGuid().ToString(), script, true);

Can anyone throw any light on why an injected control onto a PlaceHolder would prevent the ScriptManager from correctly registering the script? I am guessing this might have something to do with the lifecycle of dynamic controls, but would appreciate (for my own knowledge) if there is a correct process for the above.

Chris
A: 

The solution is to put the scripts in an outside js file (lets called 'yourDynamic.js') and re-register de file everytime you refresh the updatepanel.

I use this in the updatepanel_prerender event:

ScriptManager.RegisterClientScriptBlock(UpdatePanel1, UpdatePanel1.GetType(), "UpdatePanel1_PreRender", _
                   "<script type='text/javascript' id='UpdatePanel1_PreRender'>" & _
                   "include('yourDynamic.js');" & _
                   "removeDuplicatedScript('UpdatePanel1_PreRender');</script>" _
                   , False)

In the page or in some other include you will need this javascript:

// Include a javascript file inside another one.
function include(filename)
{
    var head = document.getElementsByTagName('head')[0];

    var scripts = document.getElementsByTagName('script');
    for(var x=0;x<scripts.length;>    {
        if (scripts[x].getAttribute('src'))
        {
            if(scripts[x].getAttribute('src').indexOf(filename) != -1)
            {
                head.removeChild(scripts[x]);
                break;
            }
        }
    }

    script = document.createElement('script');
    script.src = filename;
    script.type = 'text/javascript';
    head.appendChild(script)
}

// Removes duplicated scripts.
function removeDuplicatedScript(id)
{
    var count = 0;
    var head = document.getElementsByTagName('head')[0];

    var scripts = document.getElementsByTagName('script');
    var firstScript;
    for(var x=0;x<scripts.length;>    {
        if (scripts[x].getAttribute('id'))
        {
            if(scripts[x].getAttribute('id').indexOf(id) != -1)
            {
                if (count == 0)
                {
                    firstScript = scripts[x];
                    count++;
                }
                else
                {
                    head.removeChild(firstScript);
                    firstScript = scripts[x];
                    count = 1;
                }
            }
        }
    }
    clearAjaxNetJunk();
}
// Evoids the update panel auto generated scripts to grow to inifity. X-(
function clearAjaxNetJunk()
{
    var knowJunk = 'Sys.Application.add_init(function() {';
    var count = 0;
    var head = document.getElementsByTagName('head')[0];

    var scripts = document.getElementsByTagName('script');
    var firstScript;
    for(var x=0;x<scripts.length;>    {
        if (scripts[x].textContent)
        {
            if(scripts[x].textContent.indexOf(knowJunk) != -1)
            {
                if (count == 0)
                {
                    firstScript = scripts[x];
                    count++;
                }
                else
                {
                    head.removeChild(firstScript);
                    firstScript = scripts[x];
                    count = 1;
                }
            }
        }
    }
}

Pretty cool, ah...jejeje This part of what i posted some time ago here.

Hope this help... :)

Lucas
Hmmm, interesting mechanism - I can see how that would be useful in a few circumstances. Not 100% certain this will solve it for me, as any js inserted through script manager is being ignored by the UpdatePanel - I can't even get an alert('hello world'); to run! Not when it is embedded in the placeholder at any rate :( Will give it a run tho, always happy to be disproved :)
Chris
Keep in mind that here the insertion is made actually by javascript, thats what make it so dynamic. Let me know if it works.
Lucas
Oh... and remember that the call to the RegisterClientScriptBlock should be inside the updatepanel prerrender event... :)
Lucas
Hi Lucas - that is my problem - the custom control is inside the UpdatePanel, the custom control attempts to register the Register the block, but the UpdatePanel does not recognise it - thus NO javascript is run. I cannot pull the javascript out of the control and add it to the page - that would remove the advantage of encapsulating the behavior in the control.
Chris
A: 

I had an issue with Page.ClientScript.RegisterStartUpScript - I wasn't using an update panel, but the control was cached. This meant that I had to insert the script into a Literal (or could use a PlaceHolder) so when rendered from the cache the script is included.

A similar solution might work for you.

s_hewitt
Thanks - I'll investigate the string literal, might be a good workaround. I am using a different insertion technique as I am using static methods off System.Web.Ui.ScriptManager, not the Page.ClientScript mechanism
Chris
+3  A: 

I think you should indeed be using the Control overload of the RegisterStartupScript.

I've tried the following code in a server control:

[ToolboxData("<{0}:AlertControl runat=server></{0}:AlertControl>")]
public class AlertControl : Control{
    protected override void OnInit(EventArgs e){
        base.OnInit(e);
        string script = "alert(\"Hello!\");";
        ScriptManager.RegisterStartupScript(this, GetType(), 
                      "ServerControlScript", script, true);
    }
}

Then in my page I have:

protected override void OnInit(EventArgs e){
    base.OnInit(e);
    Placeholder1.Controls.Add(new AlertControl());
}

Where Placeholder1 is a placeholder in an update panel. The placeholder has a couple of other controls on in it, including buttons.

This behaved exactly as you would expect, I got an alert saying "Hello" every time I loaded the page or caused the update panel to update.

The other thing you could look at is to hook into some of the page lifecycle events that are fired during an update panel request:

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

The PageRequestManager endRequestHandler event fires every time an update panel completes its update - this would allow you to call a method to set up your control.

My only other questions are:

  • What is your script actually doing?
  • Presumably you can see the script in the HTML at the bottom of the page (just before the closing </form> tag)?
  • Have you tried putting a few "alert("Here");" calls in your startup script to see if it's being called correctly?
  • Have you tried Firefox and Firebug - is that reporting any script errors?
Zhaph - Ben Duguid
Hi Ben, thanks for the answer. At the moment the script is simply triggering an alert,nothing more. It is a grid control, inheriting datagrid. I would usually use Firefox/Bug, but in this case I am working in an IE only app (not my choice), won't be able to get to the screen in FF. Using IE Dev toolbar I can examine the page, but the script has not re-registered on the postback. I like the idea of the PageRequestManager, although the script is not easily exposed to the page to call as a handler. I like the ideas tho, and will use these to investigate further, thanks
Chris
A: 

I try many things and finally found that the last parameter must be false and you must add < SCRIPT > tag to the java script :

string script = "< SCRIPT >alert('hello!');< /SCRIPT>";

ScriptManager.RegisterClientScriptBlock(Page, Page.GetType(), key, script, false);

Setting true for the last parameter automatically adds the script tags.
ck
A: 

i had an issue using this in a user control (in a page this worked fine); the Button1 is inside an updatepanel, and the scriptmanager is on the usercontrol

protected void Button1_Click(object sender, EventArgs e)  
{  
    string scriptstring = "alert('Welcome');";  
    ScriptManager.RegisterStartupScript(this, this.GetType(), "alertscript", scriptstring, true);  
}

now it seems you have to be careful with the first two arguments, they need to reference your page, not your control

ScriptManager.RegisterStartupScript(this.Page, this.Page.GetType(), "alertscript", scriptstring, true);
dc2009
A: 

i have the same exact problem i could not solve the problem when update panel get updated after asyncpostback scriptmanager script does not get updated

furkan
You should not post this kind of response as an answer. It is much better to just vote up the question. Answers are meant as proposed solutions to the question. If you want to say something in addition to voting, just add it as a comment to the question. You should delete this answer.
awe
A: 

What worked for me, is registering it on the Page while specifying the type as that of the UpdatePanel, like so:

ScriptManager.RegisterClientScriptBlock(this.Page, typeof(UpdatePanel) Guid.NewGuid().ToString(), myScript, true);
Alex
A: 

using the below mentioned code in ascx.cs page helped me too :)

ScriptManager.RegisterStartupScript(this.Page, this.Page.GetType(), "focuser", "script", true);

Thanks Guys and gurlzz

Pallavi
A: 

I have a UserControl within a UserControl. Trying to reference a control that will get updated in an UpdatePanel did not work for me.

Referencing the Page within the ScriptManager.RegisterStartupScript worked immediately! :D

I would vote you dc2009, but I don't have enough reputation yet here on StackOverflow...

Eryn