RegisterStartupScript not working with UpdatePanel and Google Visualization charts - asp.net

On my ASP.NET page I am using Google Visualization charts inside of an asp:UpdatePanel. The user selects a chart they want to see from two asp:DropDownLists and then my C# code generates the JavaScript and I then call ScriptManager.RegisterStartipScript(...). When the page first loads the first default chart (i.e. first call to RegisterStartupScript) works and I can view the javascript from View Source. It is only on the postbacks that I get a blank chart and when I then go to View Source the page didn't receive the new JavaScript and it still has the old default JavaScript from the first page load.
Here is the weird behavior. If I use the exact same code but replace my Google Chart code with alert(...); then the alert() fires every time and when I view the source the script is there.
I've tried may different things and also followed such answers as here. Below is my code and any help would be appreciated, I've had other people look at this and we are all stumped.
FYI: If I remove all UpdatePanels and related items (ScriptManager and UpdateProgress) and use ClientScript.RegisterStartupScript() then everything works fine and I get the new JavaScript code on my page and the new chart appears as it should.
<asp:ScriptManager ID="ScriptMgr" runat="server" />
<asp:UpdatePanel ID="UpdatePanelData" runat="server">
<ContentTemplate>
<p>
<asp:DropDownList ID="PlotList" runat="server" AutoPostBack="true" Width="500px"
onselectedindexchanged="PlotList_SelectedIndexChanged"></asp:DropDownList>
<asp:DropDownList ID="RangeList" runat="server" Width="125px"
style="float:right;" AutoPostBack="True"
onselectedindexchanged="RangeList_SelectedIndexChanged">
</asp:DropDownList>
<br />
<asp:Label ID="PlotDescription" runat="server" Width="100%"></asp:Label>
</p>
<div id="chart_material" class="GoogleChart" style="width:100%;height:450px;"></div>
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="RangeList" EventName="SelectedIndexChanged" />
<asp:AsyncPostBackTrigger ControlID="PlotList" EventName="SelectedIndexChanged" />
</Triggers>
</asp:UpdatePanel>
<asp:UpdateProgress ID="UpdateProgressData" runat="server" DisplayAfter="500">
<ProgressTemplate>
<div class="LoadingPanel">
<asp:Image ID="LoadingImage" runat="server" ImageUrl="~/Images/loading_2.gif" AlternateText="Loading ..." ToolTip="Loading ..." style="padding: 10px;position:fixed;top:45%;left:50%;" />
</div>
</ProgressTemplate>
</asp:UpdateProgress>
And my C# code looks like this. The function DisplayPlot is called from the two DropDownList events and each list passes in themselves as 'control'.
private void DisplayPlot(Control control)
{
PlotInformation Plot = new PlotInformation(ChartDivID);
double Range = Convert.ToDouble(RangeList.SelectedValue);
string JavaScript = Plot.GetPlotScript(PlotList.SelectedItem.Text, Range);
PlotDescription.Text = Plot.GetDataPlotDescription(PlotList.SelectedItem.Text);
//string TestScript = "<script type=\"text/javascript\">\n\talert('" + PlotList.SelectedItem.Text + "');\n</script>";
ScriptManager.RegisterStartupScript(control, control.GetType(), ScriptKey, JavaScript, false);
//ScriptManager.RegisterStartupScript(control, this.GetType(), ScriptKey, JavaScript, false);
//if (!ClientScript.IsStartupScriptRegistered(ScriptKey))
// ClientScript.RegisterStartupScript(this.GetType(), ScriptKey, JavaScript);
}

I know this is late, but I spent a lot of time on the same bug.
Try changing:
ScriptManager.RegisterStartupScript(control, control.GetType(), ScriptKey,
JavaScript, false);
To
ScriptManager.RegisterStartupScript(UpdatePanelData, UpdatePanelData.GetType(), ScriptKey,
JavaScript, false);

Related

Update Panel PostBackTrigger, Update Progress not displaying

I have an update panel and update progress with a PostBackTrigger Event. But update progress is not showing when i am clicking on the button. please find the below sample code
<asp:UpdateProgress ID="UpdateProgress1" runat="server" AssociatedUpdatePanelID="updatepanelDropDownTaskType" CssClass="Token-setup-popup" DynamicLayout="true">
<ProgressTemplate>
<div id="loading" class="loading">
<asp:Image runat="server" ID="imgBusyIndicator" ImageUrl="~/images/busy-indicator.gif" />
</div>
</ProgressTemplate>
</asp:UpdateProgress>
<asp:UpdatePanel ID="updatepanelDropDownTaskType" runat="server" UpdateMode="Conditional">
<Triggers>
<asp:PostBackTrigger ControlID="btnExport" />
</Triggers>
<ContentTemplate>
<asp:Button ID="btnExport" runat="server" Text="Export To CSV" CssClass="button" CausesValidation="true" onclick="btnExport_Click" ClientIDMode="Static"/></asp:Button>
</ContentTemplate>
</asp:UpdatePanel>
My code behind
HttpResponse Response = System.Web.HttpContext.Current.Response;
Response.ClearHeaders();
Response.AppendHeader("Content-Disposition", "attachment; filename=" + FileName);
Response.ContentType = FileType;
Response.Write(content);
HttpContext.Current.ApplicationInstance.CompleteRequest();
Well Your code is Okay. Problem is with your Triggers which you are using in UpdatePanel.
Microsoft says
The UpdateProgress control renders a <div> element that is
displayed or hidden depending on whether an associated UpdatePanel
control has caused an asynchronous postback. For initial page
rendering and for synchronous postbacks, the UpdateProgress
control is not displayed.
See more details on MSDN
So you are using PostBackTrigger in your UpdatePanel which will cause a synchronous postback and UpdateProgress will not show up .
<Triggers>
<asp:PostBackTrigger ControlID="btnExport" />
// Incorrect
</Triggers>
Change it to
<Triggers>
<asp:AsyncPostBackTrigger ControlID="btnExport" />
// Correct
</Triggers>
And this will show up your UpdateProgress and will work as you are expecting.
As you have mentioned in your comments you are performing downloading as well on your Grid. Same way you could register your Button with ScriptManager. This will register your button and will aware of download button while asynchronous postbacks.
protected void GridView_RowDataBound(object sender, GridViewRowEventArgs e)
{
if (e.Row.RowType == DataControlRowType.DataRow)
{
Button btnExport = e.item.FindControl("btnExport") as Button;
if (btnExport != null)
{
((ScriptManager)this.Page.Master.FindControl("ID of your Script manager")).RegisterPostBackControl(downloadDocColumn);
// In Above line i assumed Script Manager is placed on Your master page.
}
}
}
Hope this helps...
I wrote an "Ajaxable Panel" (term explained in blog post) that may be helpful in your scenario.
http://leftyftw.wordpress.com/2011/10/01/an-ajaxable-panel/
It was geared towards SharePoint, but is perfectly applicable here.
Finally i acheived this task, with the help of iframe and endrequestHandler of sys.webforms. i explained clearly in my blog , please find the link http://bhuvanram.wordpress.com/. The Complete method has to be called in Iframe instead of calling in the same page
Try adding below to your web.config file under system.web
<xhtmlConformance mode="Transitional"/>
It may fix your problem if code is perfect.
Vote as answer if it fix your issue.

CKEditor not working properly inside update panel

I am having a problem with CKEditor inside an update panel in asp.net.
I have tab control on page with multiple CKEditor's i.e one ckeditor in each tab.
string scriptAdd = #"var editor = CKEDITOR.instances['ctl00_ContentPlaceHolder1_faqeditor']; if (editor) { editor.destroy(true); } CKEDITOR.replace('ctl00_ContentPlaceHolder1_faqeditor');";
ScriptManager.RegisterClientScriptBlock(this, typeof(Page), "", scriptAdd, true);
The above code snippet helps in rendering the editor in update panel. But when a postback is done it still shows the earlier value and not the changed one i.e the editor does not reflect the changes made after the tab is changed in the update panel.
The same thing works perfectly fine without update panel.
Is there any solution for this problem?
just force ckeditor to update the textarea on change :
var ckEditor = CKEDITOR.replace('ctl00_ContentPlaceHolder1_faqeditor');
ckEditor.on("change", function (event) {
event.editor.updateElement();
});
Sorry for the late response on this, but the answer may be helpful to others as well. You also need to do the following in code behind:
ScriptManager.RegisterOnSubmitStatement(this, this.GetType(), "updatescript", "CKEDITOR.instances['ctl00_ContentPlaceHolder1_faqeditor'].updateElement();");
Hope this helps.
<form id="form1" runat="server">
<asp:ScriptManager ID="scrpM" runat="server" EnablePageMethods="true">
</asp:ScriptManager>
<asp:UpdatePanel ID="UpdatePanel1" runat="server">
<ContentTemplate>
<asp:Button ID="btnshow" runat="server" Text="Show Hidden Editor" />
<div id="divEditor" runat="server" visible="false">
<asp:PlaceHolder ID="plCKEditor" runat="server"></asp:PlaceHolder>
</div>
</ContentTemplate>
</asp:UpdatePanel>
</form>
----------
Add editor inside a div with visible="false"
and on the button click you set visible="True"
it's works fine for me

Cannot update an image using HttpHandler, UpdatePanel and a Timer

I'm trying in ASP.NET to use a HTTPHandler to display an image and update every 5 sec.
This httphandler simply renders the current time into a Bitmap.
In aspx side, the Image is inside a AJAX UpadtePanel, and I'm using a timer to refresh the image every 5 sec.
My problem is that :
in IE9, the image is not updated at all. My HttpHandler is requested only once.
in chrome, the image is updated but it "blinks", ie every 5s it is cleared for few secs then displayed, then cleared again etc...
For debugging purpose I have also added inside the UpdatePanel a label, filled by a random value. It is well updated in both web browsers.
Here is the code in my aspx page :
<asp:ScriptManager ID="ScriptManager1" runat="server" />
<asp:Timer runat="server" ID="UpdateTimer" Interval="5000" OnTick="UpdateTimer_Tick" />
<asp:UpdatePanel runat="server" ID="TimedPanel" UpdateMode="Conditional">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="UpdateTimer" EventName="Tick" />
</Triggers>
<ContentTemplate>
<asp:Image ID="TheImage" alt="httpHandler" src="getImage.ashx?id=1" runat="server" />
<asp:Label ID="Label" runat="server" Font-Size="XX-Large" ></asp:Label>
</ContentTemplate>
</asp:UpdatePanel>
In my HttpHandler, I did not forget to disable caching like this :
cache.SetCacheability(HttpCacheability.NoCache);
cache.SetNoStore();
cache.SetExpires(DateTime.MinValue);
And to prevent my IE9 web browser caching the image, I also tried to change ImageUrl each time the timer is invoked in the aspx.cs file, like following. But my HttpHandler is still called only once when the page is displayed for the first time :
protected void UpdateTimer_Tick(object sender, EventArgs e)
{
Label.Text = ((System.Environment.TickCount / 100.0) % 360).ToString("F2");
TheImage.ImageUrl = "getImage.ashx?id=" + System.Environment.TickCount.ToString();
}
I hope my problem is well explained.
What do I do wrong?
Thanks in advance!
Some suggestions:
Add Enabled="True" to your timer.
Add the source code to your getImage.ashx to your post.
Use the asp.net tags like ImageUrl in your <asp:Image /> instead of the native html tags.
Use a div instead of an img (i.e. <asp:Panel />)
change the update mode of your UpdatePanel to Always

How to check if client script is already registered during a partial postback

Below is the code I've currently implemented.
if (!Page.ClientScript.IsStartupScriptRegistered(Page.GetType(), scriptKey))
{
ScriptManager scriptManager = ScriptManager.GetCurrent(page);
if (scriptManager != null && scriptManager.IsInAsyncPostBack)
{
//if a MS AJAX request, use the Scriptmanager class
ScriptManager.RegisterStartupScript(Page, Page.GetType(), scriptKey, script, true);
}
else
{
//if a standard postback, use the standard ClientScript method
Page.ClientScript.RegisterStartupScript(Page.GetType(), scriptKey, script, true);
}
}
I'm doing as suggested in this answer so that I can register startup script on both times i.e. when there is partial postback and a full postback.
The problem is Page.ClientScript.IsStartupScriptRegistered(Page.GetType(), scriptKey) always (even when the script is registered before) returns false when it is partial postback. And I couldn't find ScriptManager.IsStartupScriptRegistered (static) method. As a result of this, additional script is emitted on all partial/async postbacks.
Please note that I'm using script manager of AjaxControlToolkit version 4.1 i.e. ToolkitScriptManager in my masterpage. But I don't thing it has something to do with this.
UPDATE
<asp:UpdatePanel ID="ContactDetailsUpdatePanel" UpdateMode="Conditional" runat="server">
<Triggers>
<asp:AsyncPostBackTrigger ControlID="UpdateContactDetailsButton" EventName="Click" />
</Triggers>
<ContentTemplate>
<div id="ContactDetailsContent" class="contact_details_content">
<div class="customer_contactdetails_left_pane">
<div class="customer_name_field">
<asp:Label ID="CustomerNameLabel" runat="server" Text="Customer" />
<asp:TextBox ID="CustomerNameValue" runat="server" />
</div>
<div class="customer_address_field">
<asp:Label ID="CustomerAddressLabel" runat="server" Text="Address" />
<asp:TextBox ID="CustomerAddressValue" runat="server" />
<asp:TextBox ID="CustomerAddressValue1" runat="server" />
<asp:TextBox ID="CustomerAddressValue2" runat="server" />
<asp:TextBox ID="CustomerAddressValue3" runat="server" />
</div>
<div class="customer_postcode_field">
<asp:Label ID="CustomerPostcodeLabel" runat="server" Text="Postcode" />
<asp:TextBox ID="CustomerPostcodeValue" runat="server" />
</div>
</div>
<div class="customer_contactdetails_right_pane">
<div>
<asp:Label ID="CustomerContactLabel" runat="server" Text="Contact" />
<asp:TextBox ID="CustomerContactValue" runat="server" />
</div>
<div>
<asp:Label ID="CustomerTelephoneLabel" runat="server" Text="Telephone" />
<asp:TextBox ID="CustomerTelephoneValue" runat="server" />
</div>
<div>
<asp:Label ID="CustomerMobileLabel" runat="server" Text="Mobile" />
<asp:TextBox ID="CustomerMobileValue" runat="server" />
</div>
<div>
<asp:Label ID="CustomerFaxLabel" runat="server" Text="Fax" />
<asp:TextBox ID="CustomerFaxValue" runat="server" />
</div>
<div>
<asp:Label ID="CustomerEmailLabel" runat="server" Text="Email" />
<asp:TextBox ID="CustomerEmailValue" runat="server" />
</div>
<div>
<asp:Label ID="CustomerWebLabel" runat="server" Text="Web" />
<asp:TextBox ID="CustomerWebValue" runat="server" />
</div>
</div>
</div>
<div class="update_button_field">
<asp:Button ID="UpdateContactDetailsButton" runat="server" Text="Update"
onclick="UpdateContactDetailsButton_Click" />
</div>
</ContentTemplate>
</asp:UpdatePanel>
Thanks in advance.
NOTE: To be able to understand the progress on this problem, please see the comments on this answer before replying.
UPDATE
I have implemented a temporary solution to this problem by putting a check in javascript that if the script is already executing then do not execute twice. Javascript is still being spitted multiple times on every partial postback. Couldn't prevent it.
As the views to this post are increasing, I can see that there are other people who might also want answer to this problem.
If you are using this;
Page.ClientScript.RegisterClientScriptBlock(this.GetType(), "noPasswordMatch", script, true);
Then to check if it has been registered you must use this:
if (Page.ClientScript.IsClientScriptBlockRegistered(this.GetType(), "noPasswordMatch"))
if (Page.ClientScript.IsClientScriptBlockRegistered("noPasswordMatch")) doesn't work!
I ran into this same issue when writing a composite control in ASP.Net. When the control was inside an update panel Page.ClientScript.IsStartupScriptRegistered didnt work. From within the method protected override void CreateChildControls() i was doing something like
ScriptManager.RegisterStartupScript(this.Page, this.Page.GetType(), initializeTokenInputScriptKey, initializeTokenInputScript, true);
Hence I ran into a situation similar to what you describe here. What solved my problem was passing the control and its type instead of the page and page type to ScriptManager.RegisterStartupScript. Hence the code now looks,
ScriptManager.RegisterStartupScript(this, this.GetType(), initializeTokenInputScriptKey, initializeTokenInputScript, true);
Once I did this change I no longer needed to check Page.ClientScript.IsStartupScriptRegistered. Now my control works with or without update panels. No unnecessary js spitouts either. Hope this helps
I had implemented a temporary solution to this problem by putting a check in javascript that if the script is already executing then do not execute twice. Javascript is still being spitted multiple times on every partial postback. Couldn't prevent it.
I've written an extension method to check whether the script has already been registered with the ScriptManager. You can use the same principle to check startup scripts:
public static bool IsClientScriptBlockRegistered(this ScriptManager sm, string key)
{
ReadOnlyCollection<RegisteredScript> scriptBlocks = sm.GetRegisteredClientScriptBlocks();
foreach (RegisteredScript rs in scriptBlocks)
{
if (rs.Key == key)
return true;
}
return false;
}
Keep in mind your first line of code is the inverse of the method return value because of the !.
if (!Page.ClientScript.IsStartupScriptRegistered(Page.GetType(), scriptKey))
If IsStartupScriptRegistered is returning false as you say, then the if statement should evaluate true because of the !. This should cause the script to be registered as expected.
Your code is based on my answer here, which was based on ASP.NET AJAX 1.0 and ASP.NET 2.0. It may have something to do with .NET 3.5, although I believe I've used the above already in a newer project we did under 3.5 and it worked fine...
Can you post some markup to go with the code?
EDIT: Thanks for posting the markup.
I notice 2 things now:
You mentioned you are using ToolkitScriptManager. It is a control that inherits from ScriptManager. I didn't notice this before, but your code is still referencing ScriptManager directly. You said it was during async postbacks that the script isn't working, which leads me to believe it is an issue with your reference to ScriptManager. I've never used ToolkitScriptManager before so I can't give you exact code, but I can tell you that you'll likely need to update your code-behind, changing all references to ScriptManager and its methods/properties to the equivalent in ToolkitScriptManager.
Try adding a breakpoint on the if statement and make sure it's evaluation to true. I wouldn't be surprised if scriptManager is null, or scriptManager.IsInAsyncPostBack is false because you're using ToolkitScriptManager.
ScriptManager scriptManager = ScriptManager.GetCurrent(page);
if (scriptManager != null && scriptManager.IsInAsyncPostBack)
{
//if a MS AJAX request, use the Scriptmanager class
ScriptManager.RegisterStartupScript(Page, Page.GetType(), scriptKey, script, true);
}
Lastly - Your markup looks okay, other than you don't need the <Triggers> section. Triggers allow you to specify control which are outside of your update panel to cause partial renders. Any child control of the update panel within the <ContentTemplate> section will do this automatically. The button you are targeting in the Triggers section is already within the updatepanel. While I don't think this is the cause of your issue, I'd remove it anyway.
Hope this helps.
Did you mean this: ClientScriptManager.IsStartupScriptRegistered Method

Ajax callback UpdatePanel.Update() still reloading whole page

I have code in an Update Panel and even though on a button click i am inserting data into a db and simply calling Updatepanel.Update() the whole page is reloaded:
Gifts.ASPX
<table style="width:100%;">
<tr>
<td>
<asp:Label ID="Label2" runat="server" Text="Gift"></asp:Label>
</td>
<td>
<asp:UpdatePanel ID="UpdatePanel3" runat="server" UpdateMode="Conditional">
<ContentTemplate>
<asp:TextBox ID="txtNewGift" runat="server"></asp:TextBox>
</ContentTemplate>
</asp:UpdatePanel>
</td>
</tr>
<tr>
Gifts.aspx.CS
protected void cmdAddGift_Click(object sender, EventArgs e)
{
OleDbConnection objConn = new OleDbConnection(DataSource);
Random r = new Random();
int giftID = r.Next(1200, 14000);
OleDbCommand objCommand = new OleDbCommand("Insert into Gifts (GiftID, Description) values (" + giftID + ",'" + txtNewGift.Text + "')", objConn);
ExecuteCommand(objCommand);
PopulateGifts(objConn);
txtNewGift.Text = "";
UpdatePanel3.Update();
}
Any ideas why this whole page would reload instead of just the textbox getting update?
Where is the button in the above example? Inside or outside the UpdatePanel. If it is outside you will need to add it to the triggers collection of the UpdatePanel.
Also you only need to call UpdatePanel.Update() if you are changing the content of an UpdatePanel other than the one that caused the (Partial) postback.
As a side note (and personal crusade), it is recommended that a using statement is put around your DB connection.
With the markup below, the following will happen:
btnInnerPart is inside the update panel, so it will automatically cause a partial postback
btnInnerFull will cause a full postback as it has a PostBackTrigger in the trigger collection
btnOuterPart will cause a partial postback as it has an AsyncPostBackTrigger in the trigger collection
btnOuterFull will cause a full postback as it is outside the UpdatePanel
Markup:
<asp:UpdatePanel runat="server">
<ContentTemplate>
<!-- Content -->
<asp:Button runat="server" ID="btnInnerPart" Text="Inner Part" />
<asp:Button runat="server" ID="btnInnerFull" Text="Inner Full" />
</ContentTemplate>
<Triggers>
<asp:AsyncPostBackTrigger ControlID="btnOuterPart" />
<asp:PostBackTrigger ControlID="btnInnerFull" />
</Triggers>
</asp:UpdatePanel>
<asp:Button runat="server" ID="btnOuterFull" Text="Outer Full" />
<asp:Button runat="server" ID="btnOuterPart" Text="Outer Part" />
Where is the button on Gifts.ASPX? If you put the button inside the UpdatePanel or use triggers you don't need to call UpdatePanel3.Update(); from the code behind.
Also, You need to have a ScriptManager object on your page. Do you have one?
please check tag of update panel...you have to specify the trigger controls for update panel on on which the update panel will get update

Resources