How do you call a Javascript function from an ASPX control event?
Specifically, I want to call the function from the SelectedIndexChanged event of a DropDownList.
I get a little nervous whenever I see this kind of question, because nine times out of ten it means the asker doesn't really understand what's going on.
When your SelectedIndexChanged event fires on the server, it fires as part of a full postback. That means that for that code to run, the entire rest of your page's load code also had to run.
More than that, the code runs as the result of a new http request from the browser. As far as the browser is concerned, an entirely new page is coming back in the result. The old page, and the old DOM, are discarded. So at the time your SelectedIndexChanged event code is running, the javascript function you want to call doesn't even exist in the browser.
So what to do instead? You have a few options:
Change the page so the control doesn't post back to the server at all. Detect the change entirely in javascript at the client. This is my preferred option because it avoids odd onload scripts in the browser page and it saves work for your server. The down side is that it makes your page dependent on javascript, but that's not really a big deal because if javascript is disabled this was doomed from the beginning.
Set your desired javascript to run onload in the SelectedIndexChanged event using the ClientScript.SetStartupScript().
Apply the expected results of your javascript to the server-model of the page. This has the advantage of working even when javascript is turned off (accessibility), but at the cost of doing much more work on the server, spending more time reasoning about the logical state of your page, and possibly needing to duplicate client-side and server-side logic. Also, this event depends on javascript anyway: if javascript is disabled it won't fire.
Some combination of the first and third options are also possible, such that it uses javascript locally if available, but posts back to the server if not. Personally I'd like to see better, more intuitive, support for that built into ASP.Net. But again: I'm talking about the general case. This specific event requires javascript to work at all.
As Muerte said you have to just put the javascript, or a call to it on the page from the code behind. Personally I use this:
ClientScript.RegisterClientScriptBlock("customscript", "<script>simple script here</script>")
Of you can call the function if you already have a more complex one on the page instead of the stuff I have.
You can't do it directly from an event, because ASPX control event is server side.
What you can do is emit a Javascript in the ASPX event which will call the JavaScript function when the page reloads.
For example, if in your ASPX page you have a Javascript function called "DoSomething()", in you ASPX control event, add the following:
protected void btnSubmit_Click(object sender, EventArgs e)
{
Page.ClientScript.RegisterStartupScript(this.GetType(), "myEvent", "DoSomething()", true);
}
The last boolean parameter defines that tags are added automatically.
In the code behind, attach some markup to the server side control via its attributes collection. This assumes that the function is already in a client script file that is already available to the page.
MyServerDDLControl.Attributes.Add("SelectedIndexChanged", "MyClientSideFunction();");
Related
I have an asp:Button that fires a code behind function on the OnClick event. In that OnClick event several things happen, and among those things I do a check in the database for if I need to ask the user a yes or no question. For that I need a message box. First I did it like this:
protected void MyButton_Onclick(object sender, EventArgs e)
{
// lots of stuff happening
bool iNeedToAskTheUser = INeedToAskTheUser(stuff);
if (iNeedToAskTheUser)
{
DialogResult result = MessageBox.Show("Do you want to fix all objects?", "Fix objects", MessageBoxButtons.YesNo);
if (result == DialogResult.Yes) // do stuff
}
// some other stuff
}
This works fine locally but not when deployed, so I figure I would need to use ScriptManager.RegisterStartupScript instead. I could just add javascript on the ASPX page that fires up a dialog and saves the response in a hidden control that I can then look at, but I don't want to fire up the dialog unless I have to, which I check for before I do the DialogResult in the code above. So I can't do that immediately when the user clicks the button.
Is there any way I can use ScriptManager.RegisterStartupScript in "the middle" of my _OnClick code so that I can choose whether or not to actually show the button, and then also know if the user clicked yes or no, (preferably) without doing a postback?
I've been thinking and testing two different solutions:
Use ScriptManager.RegisterStartupScript in code behind to fire a JavaScript confirm function on the ASPX page. The JavaScript function would set a value in a hidden control depending on if the user answered yes or no and then my code behind stuff would check the value of that hidden field and act upon that. The problem with that is that once ScriptManager.RegisterStartupScript fires it doesn't wait for the JavaScript function to "finish", ie wait for the user to reply to the confirm(). So the value in the hidden control will always be empty because the code behind gets to the check of that control before the user has a chance to respond to the confirm(). So that's a no go.
Use ScriptManager.RegisterStartupScript in code behind to open up a new ASPX page that asks the user the question and then does all the work in response to the user's answer in that page. The problem then is to pass the object that the new ASPX page needs to do work on in response to the user's response.
I'm sure there are great solutions using Ajax or jQuery but this is a fairly simple function that shouldn't take too long to develop, so that is kind of out of scope for this.
Instead I'll go with a solution where I know what the user will respond to the question before they click the button. (While silently muttering under my breath: "It's 2019 and there's no good way to fire up a yes/no dialog from code behind in a .Net web project...". I need to get back to not working with web).
I know that ASP.NET controls such as the button have the postback event model. And checking whether the page.IsValid is dependent on events and postback in order for the validation to kick in.
But what if I have a button using regular HTML inside my .aspx (and I don't want to use the asp.net button...please do not ask me why) yet still want to take advantage of calling Page.IsValid?
For example, lets say my .aspx page has 2 buttons:
<asp:ImageButton runat="server" ID="cmdPlaceOrder" OnClick="cmdPlaceOrder_Click" ImageUrl="images/someButton.gif" />
and that was there in the page, someone else had created that a while back. In the cmdPlaceOrder we check for Page.IsValid:
protected void cmdPlaceOrder_Click(object sender, EventArgs args)
{
if (!IsValid)
return;
... rest of logic
}
That's standard. Now what if I add a non-ASP.NET button like this in the .aspx page, used to place the order (but for a different kind of order seperate from the existing place order button above):
<img src="images/buttonPayGoogleCheckout.gif" alt="Pay with Google"/>
So on click of the hyperlink, the page posts back to itself (same url). I check the url for a querystring param flag that if set calls the method below that I created which is basically a similar method as the above but with a bit of different logic in it:
protected void PlaceGoogleCheckoutOrder()
{
if (!IsValid)
return;
... rest of logic here, but I can't get to it because there is no event model to allow IsValid to work
}
Obviously I'm not tying in an event model to this therefore once it hits the check for Page.IsValid it errors with the following message at runtime:
Page.IsValid cannot be called before validation has taken place. It should be queried in the event handler for a control that has CausesValidation=True and initiated the postback, or after a call to Page.Validate.
But I still want to be able to call this validation, the validation that's already been setup in our .aspx. I don't want to reinvent the wheel on this and I don't in this case want to use an ASP.NET based button (do not ask me why, I have my reasons and it's too long to get into that).
I want to know how I can still get that Page.IsValid check to work for a non-event driven button using . I'm not sure how to hook up an event to do so that still hooks in after the redirect and allows that code to still validate.
I tried adding Page.Validate(); inside my PlaceGoogleCheckoutOrder() method right before the check for Page.IsValid but I still get the same error.
After looking at MSDN on Page.Validate() (http://msdn.microsoft.com/en-us/library/0ke7bxeh.aspx) and it states "The validation group is determined by the control that posted the page to the server. If no validation group is specified, then no validation group is used."
So that's why nothing happened. So I'm not sure how to get ASP.NET in this case to know about the control (in this case my ) that posted the page to the server so that a validation group IS used. I guess I could add a runat="server" to my ...but doubt that's all I need to do here.
The trick with your normal button is that it never does a post back because your href attribute has some other url there. If you want to check if the page is valid, you have to post back to your page class first to make that check and then redirect from there.
What you can do to make this happen with a normal anchor (<a >) tag is process that anchor's onclick event in javascript, do any client side work you want, and then call the __doPostBack() javascript function.
You can see an example of how to call __doPostBack() on msdn here:
http://msdn.microsoft.com/en-us/library/aa720099(VS.71).aspx
It's from .Net 1.1, but still accurate.
Here's the odd situation:
we have a piece of javascript library that is being called on our onload of aspx page.
It works everytime for us, but the clients that have low speed modems get an error, because the object is not getting initialized and the aspx page is already loaded.!!
Is there any suggestions on how to call this piece of js code?
Thanks,
make sure you have your end tags.. i have seen onLoads in the not working right when your core tags are incomplete or not properly formatted
The onload even happens when everything in the page is loaded. If you have some script that is loading from a different server (ads, statistics), the onload event won't fire until those are loaded also. If their server is having problems, your onload may never fire at all, or after several minutes when the browser gives up waiting.
Instead of using onload you could put your code in a script tag as early as possible in the page, i.e. after the last element that the script needs.
If you have some external script that doesn't need a specific place in the page (statistics for example), you can move it to the bottom of the page to minimise the risk of interference with the rest of the page.
With JQuery you can call your functions with ready event :
$(document).ready(function() {
// call your functions here
});
The event will be called when the DOM is loaded.
I have noticed that window.onunload event fires off AFTER page_load event which makes no sense.
This behaviour is creating an issue for me - in my unonload I clear the session, so if the Page_Load first BEFORE onunload, there are errors on the page displayed.
I would expect the javascript onunload to fire BEFORE Page_Load....is that the correct assumption?
TO CLARIFY:
Let's assume I am on page test.aspx, then I click on the link that goes to the same page (say I click on a menu), what I observe is that Page_Load fires first, then onunload fires off.
Makes no sense at all.
It's a browser-specific behaviour. Chrome and FF will send a GET requst BEFORE onunload is fired, IE8 will execute onunload first. Not sure, how the other browser handle it. Better not rely on this functionality.
Have you considered using a common base class for your pages, and clearing the session in there if the request isn't a postback (I assume that you're using session for postbacks)?
public class BasePage : System.Web.UI.WebControls.Page {
protected override OnPreInit (EventArgs e) {
// Get in nice and early, however you could use OnInit if you prefer
if (!Page.IsPostBack) {
Session.Clear();
}
}
Then your pages that need to clear session can be declared as:
public class SpecialPage : BasePage {
// Your page logic goes here.
// Note that if you need to do work in OnPreInit here you should call
// base.OnPreInit(e) first.
}
I would guess that window.unload is actually firing only when you're going to have to RENDER the new page you navigated to (aka the old DOM is being torn down in place of some new HTML). The browser doesn't know what to render until the response comes back from the server with the HTML to display. That HTML isn't generated until the page lifecycle completes, which includes Page_Load. Hence the page_load before the window.unload?
In any case, if you can clear the session during window.unload, why not just clear it in response to some user interaction and be a bit more explicit about it?
Edit: Could you also try window.onbeforeunload?
The onunload event does fire before the request for the new page is fired off to the server, so it definitely fires before the Page_Load method runs on the server.
The problem is most likely that you are sending another request to the server from the onunload event. As the IIS only handles one request at a time from each user, this request will be queued and executed after the request for the new page.
You can write an utility function which will handle removing of the session variables and then call that function in the respective menu click events. That should be simpler to use since window unload will fire after page load only.
It sounds like you are using the Session to save temporary variables that change from page to page. I would say the Session is not really suitable for this kind of scenario. A better solution would be to use the Httpcontext's Item collection which is scoped only on a per request basis. It's works just the same as the Session when storing data.
Context.Items["myvariable"] = "some data";
As it's only scoped on a per request basis, there is no need to use javascript to clear the items you have stored on each page request.
I need the ability to temporarily turn off the partial page update behavior for an ASP.NET Ajax / UpdatePanel based page. (The reason is to circumvent the issue where IE blocks "automatic file downloads" for downloads generated as a result of this postback, but I don't want to distract from my original question)
I looked at the client side javascript libraries hoping to find a switch somewhere. I think a solution might involve using javascript to override the 'onclick' event handler for the control that acts as the trigger, and then calling "submit" on the form itself..
Also, using the EnablePartialRendering property on the server-side ScriptManager control won't work because that is done when the page is being built. I need to be able to do this as a result of switching a drop down list box.
Any ideas?
Cheers!
/ Sean
Well, after much trial and error, I found two approaches that seemed to work:
Use Javascript to manually submit the top level form associated with the page. This usually has the ID of "form1".
Create a button that is outside of any UpdatePanels and use Javascript to click the button.
I wound up using the second approach, since it allowed me to handle the event with a specific routine without the need to guess that my postback came from a Javascript call.
This is an example of the code that performed the postback:
...
if (isDownload) {
document.getElementById('FullPostbackSubmitter').click();
return;
}
...
Hope this helps someone else!
You can set the EnablePartialRendering property of your ScriptManager to false.