ASP.Net - Javascript inside AJAX UpdatePanel - javascript

I am running into an issue with running javascript from an external javascript file inside of an UpdatePanel. I am trying to get a color picker working inside of a ListView. The ListView is inside of an UpdatePanel.
I am using this color picker.
Here is what I have narrowed it down to:
If I use the color picker on a textbox outside of an UpdatePanel, it works perfectly fine through all postbacks.
If I use the color picker on a textbox inside of an UpdatePanel, it works, until I do an async postback(clicking on an "EDIT" button in the ListView). Once the UpdatePanel has done the postback, the textbox will no longer show the color picker when clicked. The same occurs when the textbox is in either the InsertItemTemplate or EditItemTemplate of the ListView.
If you would like to replicate it, simply download the color picker(it's free), then add this to a webpage...
<asp:ScriptManager ID="ScriptManager1" runat="server">
</asp:ScriptManager>
<div>
<asp:UpdatePanel ID="panel1" runat="server">
<ContentTemplate>
<asp:TextBox runat="server" ID="textbox" CssClass="color" />
<asp:Button ID="Button1" runat="server" Text="Button" />
</ContentTemplate>
</asp:UpdatePanel>
</div>
When the page loads, the color picker works fine. When you click on the button(which does a postback), the color picker will no longer work.
Any ideas?

After an asynchronous roundtrip, any startup scripts will not be run, which is likely why it doesn't work after the AJAX callback. The color picker likely has functions which need to be executed on page load.
I've run into this so many times that I wrote a small method to register my scripts in the code-behind, which handles both async and non-async round trips. Here's the basic outline:
private void RegisterClientStartupScript(string scriptKey, string scriptText)
{
ScriptManager sManager = ScriptManager.GetCurrent(this.Page);
if (sManager != null && sManager.IsInAsyncPostBack)
{
//if a MS AJAX request, use the Scriptmanager class
ScriptManager.RegisterStartupScript(this.Page, this.Page.GetType(), scriptKey, scriptText, true);
}
else
{
//if a standard postback, use the standard ClientScript method
scriptText = string.Concat("Sys.Application.add_load(function(){", scriptText, "});");
this.Page.ClientScript.RegisterStartupScript(this.Page.GetType(), scriptKey, scriptText, true);
}
}
I actually baked the above into a base page class so that any page I'm working with can call this.RegisterClientStartupScript(...). To do that, simply create a base page class and include it there (making sure to mark protected not private or your inheriting page classes won't be able access it).
With the above code, I can confidently register client scripts regardless of whether the page is doing a postback or callback. Realizing you are using external script files, you could probably modify the above method to register external scripts rather than inline. Consult the ScriptManager class for more details, as there are several script registering methods...

After looking at the jscolor source code, I noticed that it initializes everything on window load. So, you will probably need to re-init with something like this (inside the UpdatePanel):
function yourInit(){
/* keep in mind that the jscolor.js file has no way to determine
that the script has already been initialized, and you may end
up initializing it twice, unless you remove jscolor.install();
*/
if (typeof(jscolor) !== 'undefined'){
jscolor.init();
}
}
if (typeof(Sys) !== 'undefined'){
Sys.UI.DomEvent.addHandler(window, "load", yourInit);
}
else{
// no ASP.NET AJAX, use your favorite event
// attachment method here
}
If you decide to put the jscolor script inside the UpdatePanel, you will also need to add something like this to the end of the jscolor.js:
if(Sys && Sys.Application){
Sys.Application.notifyScriptLoaded();
}

Have you tried ScriptManager.RegisterStartupScript which allows you to "adding JavaScript from the server to a page when performing an asynchronous postback" ?

I would guess that the jscolor.js code which runs to setup the color picker is only being called when your page first loads, so when the control is regenerated on the server, you lose the changes jscolor made. Could you register some javascript to be called in your code behind so that it would call the init method on jscolor when your asynch call completed?

Related

Calling Jquery whilst partial postback on updatepanel

I have a very strange issue on Jquery and partial postback on updatepanel.
What I have done is created a jquery logic in code behind and used :
Page.ClientScript.RegisterStartupScript(this.GetType(), "jsSlider" + select.ClientID, sb.ToString());
to create the Jquery Slider feature in a repeater. However Whats happening is when I put this within inside updatepanel it runs ok and the jquery slider works however any partial postback and I lose my lovely jquery slider feature because I need to re-bind the slider feature back after each partial postback.
How can I do this using similar code like Page.ClientScript.RegisterStartupScript(this.GetType(), "jsSlider" + select.ClientID, sb.ToString());
Is there another way to say Page.ClientScript.EVERYPOSTBACK(this.GetType(), "jsSlider" + select.ClientID, sb.ToString()); or something?? I am open to other suggestions?
you can use the "pageLoad" function in your javascript on your front end code. The pageLoad function gets called on the initial pageload and after every partial postback. If there are things that only need to be called on the initial page load, you would still want to put them in document ready.
<script type="text/javascript">
function pageLoad()
{
//...
//anything you want to happen every time the page loads or after a partial postback
//...
//your javascript here... below an example of using jquery on some asp.net control.
$('#<%= select.ClientID %>').foo('bar');
}
</script>
http://www.asp.net/ajax/documentation/live/overview/AJAXClientEvents.aspx has some more details about this about 1/3 of the way down the page.
If you still need the answer, there's an analog of ClientScript.RegisterStartupScript for UpdatePanel's partial postback. Try ScriptManager.RegisterStartupScript instead.

Server side JavaScript action

I coded a chat script using AJAX.NET. For every button click I am using the following sample of code in which I am using OnClientClick function to scroll down on every button click i.e. update.
<asp:Button ID="btn_msg" runat="server" Text="Submit" OnClick="btn_msg_Click" OnClientClick="scrolldown('div1')" />
This results fine on the page I am working but in the receiver side scroll bar is not getting down on update. I guess changing the option OnClientClick to some server action will help. I tried adding OnClick="btn_msg_Click; scrolldown('div1');" but this is not working. Is there any alternate way to fulfill my action.
At first glance, I believe Anton is correct. The reason you are seeing this behavior is the order in which everythings runs. The client script runs first. Then the server script. The server script causes a postback( or even via an update panel ), causing it to render the html again, losing the scroll bar position.
Anton's code causes the scrolldown function to run once the ajax postback is complete.
A side note:
If I were doing this, I'd remove the AJAX.NET completely and switch to jquery. You have a lot more control over this kind of stuff.
You need to hook on the endCallback event to scrolldown.
The moment you try to scroll down content is not yet delivered.
Try it this way:
<body onload=”load()”>
<script>
function EndRequestHandler()
{
scrolldown('div1');
}
function load()
{
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(EndRequestHandler);
}
</script>

It is possible that calling asp.net function as being used javascript codes?

Forinstance there is a asp.net function. I want to run that function from javascript codes. is this possible ? if it is , how?
This is not the best way to do it, its a quick fix, cunning, but it works!
just add a asp button somewhere in the page and in the button click function, call the method you want to call from javascript.
suppose you have a c# function in your code behind like
public void doSomething() {...}
then the button function will something be like:
protected void button1_onClick(object sender, eventArgs e)
{
doSomething();
}
and your aspx page will have a button like this, make sure you add style property to hide the button (if you want to hide it)
<asp:button ID="button1" runat="server" text="" style="display:none"
class="NinjaButton" onClick="button1_onClick" />
now, when you want to call the function, just click the invisible button through javascript (or even better, jquery)
suppose you want to call the function when the mouse moves over a div, you can do this:
<div id="divSomething" OnMouseOver="$('.NinjaButton').click()">
....
</div>
Remember, the NinjaButton in the jquery on mouseover is just the class name of that button. make sure you dont have that class to any other button!
There's no such thing as asp.net function. If you mean a .NET method which is defined in the code behind of an ASP.NET page you could take a look at PageMethods. And here's an example using jQuery. Scott Gu has also blogged about them. Note that the method needs to be static.

ASP.NET Register Script After Partial Page Postback (UpdatePanel)

I have a simple form (textbox, submit button) which is wrapped in an update panel.
<asp:UpdatePanel ID="ReplyUpdatePanel" UpdateMode="Conditional" runat="server">
<ContentTemplate>
<asp:Textbox id="ReplyTextBox" runat="server"/>
<asp:Button id="SubmitButton" OnClick="SubmitButton_Click" runat="server"/>
<ContentTemplate>
</asp:UpdatePanel>
So, when i click the button, the server-side click event is fired (SubmitButton_Click), stuff happens to the db, and the page is re-rendered (asynchronously).
Here's my issue - i need to execute some JavaScript after all the "stuff happens to the db".
In other words, i need to create some JavaScript whose data/parameters are based on server-side logic.
I've tried this:
Page.RegisterStartupScript
and this
ScriptManager.RegisterStartupScript
Neither work (nothing happens).
Now i now i can hook into the .add_pageLoaded function using the client-side AJAX libary (to execute client-side scripts once partial update is complete), but the problem is i need data from the server that is created on the button click event.
Ie:
Sys.Application.add_init(function () {
Sys.WebForms.PageRequestManager.getInstance().add_pageLoaded(function (sender, args) {
var panels = args.get_panelsUpdated();
for (var i = 0; i < panels.length; i++) {
// check panels[i].id and do something
}
});
});
The only "hack" i can think of at the moment is to do the above, but call a web service, getting all the data again then executing my script. I say "hack" because i shouldnt need to do an asynchronous postback, hook into the after-partial-postback event handler then call the server again just to get the info that was previously posted.
Seems like a common problem. And no, i cannot remove the UpdatePanel (even though i would love to), don't want to waste time arguing why.
Any non-hacky ideas?
EDIT
Clarification on the data i need sent to script:
I type some text in the textbox, click submit, then the server creates a database record and returns an object, which has properties like ID, Name, URL, Blah, etc. These are the values that the script requires.
So if i were to call a web service from the client-code, in order to get the values that were just created, i would need to do some hacks (get last record modified that has the value of the textbox). Not ideal, and neither is two AJAX calls for one form post. (update panel postback, then web service call).
Instead of add_pageLoaded you'll want add_endRequest here, like this:
Sys.WebForms.PageRequestManager.getInstance().add_endRequest(function (sender, args) {
//check here...
});
The difference is that endRequest runs when any partial postback comes back.

ASP.NET postback with JavaScript

I have several small divs which are utilizing jQuery draggable. These divs are placed in an UpdatePanel, and on dragstop I use the _doPostBack() JavaScript function, where I extract necessary information from the page's form.
My problem is that when I call this function, the whole page is re-loaded, but I only want the update panel to be re-loaded.
Here is a complete solution
Entire form tag of the asp.net page
<form id="form1" runat="server">
<asp:LinkButton ID="LinkButton1" runat="server" /> <%-- included to force __doPostBack javascript function to be rendered --%>
<input type="button" id="Button45" name="Button45" onclick="javascript:__doPostBack('ButtonA','')" value="clicking this will run ButtonA.Click Event Handler" /><br /><br />
<input type="button" id="Button46" name="Button46" onclick="javascript:__doPostBack('ButtonB','')" value="clicking this will run ButtonB.Click Event Handler" /><br /><br />
<asp:Button runat="server" ID="ButtonA" ClientIDMode="Static" Text="ButtonA" /><br /><br />
<asp:Button runat="server" ID="ButtonB" ClientIDMode="Static" Text="ButtonB" />
</form>
Entire Contents of the Page's Code-Behind Class
Private Sub ButtonA_Click(sender As Object, e As System.EventArgs) Handles ButtonA.Click
Response.Write("You ran the ButtonA click event")
End Sub
Private Sub ButtonB_Click(sender As Object, e As System.EventArgs) Handles ButtonB.Click
Response.Write("You ran the ButtonB click event")
End Sub
The LinkButton is included to ensure that the __doPostBack javascript function is rendered to the client. Simply having Button controls will not cause this __doPostBack function to be rendered. This function will be rendered by virtue of having a variety of controls on most ASP.NET pages, so an empty link button is typically not needed
What's going on?
Two input controls are rendered to the client:
<input type="hidden" name="__EVENTTARGET" id="__EVENTTARGET" value="" />
<input type="hidden" name="__EVENTARGUMENT" id="__EVENTARGUMENT" value="" />
__EVENTTARGET receives argument 1 of __doPostBack
__EVENTARGUMENT receives argument 2 of __doPostBack
The __doPostBack function is rendered out like this:
function __doPostBack(eventTarget, eventArgument) {
if (!theForm.onsubmit || (theForm.onsubmit() != false)) {
theForm.__EVENTTARGET.value = eventTarget;
theForm.__EVENTARGUMENT.value = eventArgument;
theForm.submit();
}
}
As you can see, it assigns the values to the hidden inputs.
When the form submits / postback occurs:
If you provided the UniqueID of the Server-Control Button whose button-click-handler you want to run (javascript:__doPostBack('ButtonB',''), then the button click handler for that button will be run.
What if I don't want to run a click handler, but want to do something else instead?
You can pass whatever you want as arguments to __doPostBack
You can then analyze the hidden input values and run specific code accordingly:
If Request.Form("__EVENTTARGET") = "DoSomethingElse" Then
Response.Write("Do Something else")
End If
Other Notes
What if I don't know the ID of the control whose click handler I want to run?
If it is not acceptable to set ClientIDMode="Static", then you can do something like this: __doPostBack('<%= myclientid.UniqueID %>', '').
Or: __doPostBack('<%= MYBUTTON.UniqueID %>','')
This will inject the unique id of the control into the javascript, should you wish it
Per Phairoh: Use this in the Page/Component just in case the panel name changes
<script type="text/javascript">
<!--
//must be global to be called by ExternalInterface
function JSFunction() {
__doPostBack('<%= myUpdatePanel.ClientID %>', '');
}
-->
</script>
Using __doPostBack directly is sooooo the 2000s. Anybody coding WebForms in 2018 uses GetPostBackEventReference
(More seriously though, adding this as an answer for completeness. Using the __doPostBack directly is bad practice (single underscore prefix typically indicates a private member and double indicates a more universal private member), though it probably won't change or become obsolete at this point. We have a fully supported mechanism in ClientScriptManager.GetPostBackEventReference.)
Assuming your btnRefresh is inside our UpdatePanel and causes a postback, you can use GetPostBackEventReference like this (inspiration):
function RefreshGrid() {
<%= ClientScript.GetPostBackEventReference(btnRefresh, String.Empty) %>;
}
While Phairoh's solution seems theoretically sound, I have also found another solution to this problem. By passing the UpdatePanels id as a paramater (event target) for the doPostBack function the update panel will post back but not the entire page.
__doPostBack('myUpdatePanelId','')
*note: second parameter is for addition event args
hope this helps someone!
EDIT: so it seems this same piece of advice was given above as i was typing :)
If anyone's having trouble with this (as I was), you can get the postback code for a button by adding the UseSubmitBehavior="false" attribute to it. If you examine the rendered source of the button, you'll see the exact javascript you need to execute. In my case it was using the name of the button rather than the id.
Have you tried passing the Update panel's client id to the __doPostBack function? My team has done this to refresh an update panel and as far as I know it worked.
__doPostBack(UpdatePanelClientID, '**Some String**');
First, don't use update panels. They are the second most evil thing that Microsoft has ever created for the web developer.
Second, if you must use update panels, try setting the UpdateMode property to Conditional. Then add a trigger to an Asp:Hidden control that you add to the page. Assign the change event as the trigger. In your dragstop event, change the value of the hidden control.
This is untested, but the theory seems sound... If this does not work, you could try the same thing with an asp:button, just set the display:none style on it and use the click event instead of the change event.
You can't call _doPostBack() because it forces submition of the form. Why don't you disable the PostBack on the UpdatePanel?

Categories