ASP.NET/JavaScript - Script Registration/Redirection Problem - javascript

My page has a submit button on it (server-side button).
Here's my code for the click event:
protected void SubmitButton_Click(object sender, EventArgs e)
{
db.SaveSomething();
Page.ClientScript.RegisterStartupScript("someScriptWhichReliesOnServerData");
Response.Redirect("SomeOtherPage.aspx");
}
Now, the problem is, i register the JavaScript using Page.ClientScript.RegisterStartupScript, but this will have no effect as the page is not being re-rendered on postback (which is where the script WOULD be executed), because instead a Response.Redirect happens.
The only solution i can think is to make the page i redirect to "aware" that im trying to execute some JavaScript, be it QueryString, HttpContext.Current.Items, or (gulp) Session.
QueryString - not an option, as it's JavaScript im trying to execute.
HttpContext.Current.Items - also not an option because im doing a Response.Redirect (which loses the request-level data, and i also cannot use Server.Transfer because this doesn't play nice with URL Rewriting).
Session - of course, but not ideal.
Any other ideas/suggestions?
EDIT for Clarification:
The JavaScript im executing is a call to a Facebook client-side API to publish to the user's wall. It has to be done client-side. I pass to the script things like "title", "message", "action links", etc. Basically a bunch of JSON. But the key here is that this data is created on postback, so i cant just execute this function on client-side click.
So what im trying to accomplish is on submit button click, execute some javascript and do a redirect (does not have to be in that order, just both need to happen).

I think what you are experiencing is the unfortunate clashing of two different paradigms here. On the one side you have an AJAX style API you want to take advantage of, and on the other side you have the ASP.Net page postback model.
Now, while these two are not mutually exclusive, it can present some challenges. I agree with Dan that your best bet is to bend a little more towards the AJAX approach instead of the other way around.
A nice feature in ASP.Net is the ability to turn a single static method in your page into a pseudo web service. You can then use the ScriptManager to generate client-side proxy classes to call that method for you, but you can use whatever client side library you want.
A very simple example:
In your codebehind for you Page
[WebMethod]
public static Person GetPerson(Int32 id, String lastName)
{
return DataAccess.GetPerson(id, lastName);
}
If you were using the ASP.Net AJAX library to handle this for you, then you would need to enable page methods to generate the client-side proxies.
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePageMethods="true">
</asp:ScriptManager>
Then you could call that from client-side script like so:
function CallGetPerson()
{
var id = $get("txtPersonId").value;
var lastName = $get("txtLastName").value;
// PageMethods is a class that is part of the ASP.Net AJAX
// client-side libraries and will contain your auto-generated
// proxy methods for making XHR requests.
PageMethods.GetPerson(id, lastName, OnGetPersonComplete);
}
function OnGetPersonComplete(result)
{
faceBookApi.DoSomeStuffWithJson(result);
window.location = "NewPage.aspx";
}
Now again, this is a contrived example, and what you are posting to the server may be very complicated, but you get the general idea of what can be accomplished using the built in framework components.
I hope this helps.

If you use Response.Redirect, the java script you registered at the previous line will not executed. I think what you want to do after clicking the submit button is:
Save something
Execute javascript
Redirect to another page
Here you can use:
protected void SubmitButton_Click(object sender, EventArgs e)
{
db.SaveSomething();
Page.ClientScript.RegisterStartupScript("someScriptWhichReliesOnServerData");
Page.ClientScript.RegisterStartupScript("window.location.href=XXXXXX");
}
That is, using javascript to redirect the page instead of Response.Redirect.

Could you run the JavaScript on the second page?
Other than that, your options are somewhat limited. You could use AJAX to get the data you need from the server and then redirect. That would improve the UX since at the very least you wouldn't have extra page loads to run your intermediary JavaScript.
Another option would be to use Server.Transfer(...), which works similarly to Response.Redirect, but it doesn't send a redirect header to the client. It simply tells the server "stop running the current page and start executing a new page". Context.Items will remain in scope between the 2 classes because you're only transferring the responsibility of responding to the request, not the entire context of the request.
You could also combine these 2 solutions. Use Server.Transfer to keep Context.Items values in scope and then render the JS on the second page using whatever values you kept from the first page.

Related

VB.NET calls Javascript function. How do I get javascript function to complete before VB.NET completes?

In a web application I am using a button_Click method in VB.Net to occur when a button is clicked.
I have the following line at the top of my VB.NET method:
ScriptManager.RegisterStartupScript(Me, Me.GetType(), "myFunction", "myFunction();", True)
I want that script to finish before my VB.NET script carries on. Basically, I have validation in my javascript that I want to complete before the VB.NET takes the "validated" data and inserts it into a database.
This betrays a misunderstanding of how web forms work. Here's what really happens:
A user requests your page from their browser for the first time
Your web server runs the ASP.Net page life cycle in order to send an html response
The web server destroys the page class instance it used to complete the request.
The response from the server arrives and is rendered by the user's browser.
The user clicks your button, resulting in a new http request.
The browser destroys the existing html DOM.
The request arrives at the web server, which then runs the full ASP.Net life cycle again, including the Page_Load method.
This time the data included with the request indicates to ASP.Net that it should also run your button's Click code.
The button registers the javascript to run when the page loads in the browser.
The page lifecycle completes, and ASP.Net sends it's HTML response back to the browser.
ASP.Net destroys the page class instance again.
The response arrives at the browser, which renders it from scratch by creating a whole new html DOM.
The page's javascript load event fires, and some javascript included with ASP.Net pages kicks off the javascript startup script registered by the button.
I need to point out some things about this process, namely that order between steps 3 and 4, steps 6 and 7, and steps 11 and 12 are accurate. When there is working page visible in the browser, the server has already moved on and destroyed anything used to create that page (except Session variables). While VB.Net code is running, the browser doesn't even have a page to show yet.
What you should learn from this is that at time the javascript runs, not only has the VB.Net method already finished, but the entire page class was already destroyed. There's an idea of continuity here for both the browser's web page and the VB.Net Page class instance that just doesn't happen. It's just nice that all this happens in a way that is mainly transparent to the user.
Fortunately, there are some things you can do to avoid this full process. You might look into using an UpdatePanel for part of your page, changing the button to trigger a WebMethod, or translating more of the VB.Net code into javascript in the first place. However, all of these will likely require significant re-thinking of how your page is going to work. In this case, you might find and a Validation control best fits your needs.
This is assuming that myFunction is a javascript function existing on your client side. It will call myFunction on the client side.
<asp:Button ID="btntest" runat="server" Text="Add Record"/>
<asp:CustomValidator ID="myCustomValidator" runat="server" ControlToValidate="someControl" ErrorMessage="Validation Error" ClientValidationFunction="myFunction"></asp:CustomValidator>
This is assuming that you javascript is doing some validation as well. It would look something like this. If args.IsValid = false, then the validator won't allow a postback and the vb.net code won't execute. This is the point of a validator.
function myFunction(sender, args) {
var someControl = document.getElementById(sender.controltovalidate).control;
//Let's assume someControl is a textbox and we don't want it bigger than 10
if (someControl.value > 10) {
args.IsValid = false;
} else {
args.IsValid = true;
}
}
Hopefully, this gets you going. Let me know if something isn't working right and you need more help.

ASP.NET call a Javascript function

I'm working on a project that uses IP Payments to process transactions. The project involves a web form written in ASP with Code-Behind written in C#.
IPP offers an iFrame implementation, where you can put an iFrame in your page and display a small IPP page with fields for entering credit card information. The idea behind this is that the credit card info will only be handled by IPP and never by the server running the page, thus there is no requirement to ensure that card data is kept secure.
In order to display the IPP page in the iFrame though, a session needs to be initiated with IPP. The server initiates the session, and passes in a SessionID variable. Upon a successful session initiation, a Secure Session Token is returned to the server. The server then needs to "force" the client's browser to GET or POST the SessionID and the SST (Secure Session Token) to the IPP website. This is where my problem is.
I wrote a Javascript function in the ASPX page that would accept two parameters - the SessionID and SST - and send them to the IPP website. I'm now trying to call this Javascript function from my C# code upon successful initiation of the IPP session. However, I have been completely unable to do so.
I've done a lot of searching, and the one answer I keep coming across is to use either RegisterStartupScript or RegisterClientScriptBlock. The problem is, these seem to insert text directly into the page, rather than calling an existing function. Assuming I inserted my function into the page via one of those functions rather than writing it into the page myself, it still doesn't solve my problem of how to call said function.
Now it is possible that I'm going about this the wrong way, and there's a much better way to get the client's browser to GET/POST the SessionID and SST; if so, please tell me. I'm inexperienced with web programming and am thus learning as I go and making up solutions along the way that are quite likely not ideal.
Thanks in advance.
I think this should work:
Lets say you have something like this in your HTML:
<html>
<head>
<script>
function sendValuesToIPP(sessionId, sst){
//do stuff
}
</script>
</head>
</html>
If you do this in your C# code it should work
ClientScriptManager.RegisterStartupScript(
this.Type,
"some_key_you_want_to_identify_it",
string.Format("sendValuesToIPP('{0}','{1}')", SessionID, SST),
true);
Keep in mind that I'm assuming you have SessionID and SST properties server side, you can get them from wherever you want and just add them to the string that will actually call the function when registered in your ASPX.

simulating hyperlink.target="_parent" with response.redirect

how can I simulate hyperlink.target="_parent" with response.redirect in ASP.NET codebehind (C#), I want to redirect to a page (from code behind) but as I'm in a 2-frame window, the whole page should be redirected, i.e. something like hyperlink.target="_parent", I suppose it should be possible via JavaScript, can you give some help please? I want something cross-browser of course
thanks
You can manipulate other frames/windows only on the client-side (through javascript, user interaction etc.)
Response.Redirect is a server-side construction; the server doesn't know anything about your frames and cannot perform the necessary action. The workaround could be to say the page to execute javascript code when it will be returned to the client.
So ClientScript.RegisterStartupScript method (you already mentioned it in your comment) could be the best option here.

MVC3, switching between Views in the same page

I am working on a MVC project that is supposed to have one page only, with two zones. On one zone I have a Google Map with markers, and the second zone is populated with the selected marker's details.
The details view has a button that when clicked should change the entire view into edit mode without refreshing the page or redirecting it. I have used two views, for details and edit and with the help of ajaxForm function I am switching back and forth between these two views. I'm adding the ajaxForm on documentready for edit view.
<script type="text/javascript">
// wait for the DOM to be loaded
$(document).ready(function() {
// bind 'myForm' and provide a simple callback function
$('#currentDiv').ajaxForm(function(data) {
$('#currentDiv').html(data);
});
});
</script>
The problem appears when on server-side an error appears while trying to save data from edit view and I want to return to the same edit view with the errors displayed. The ajaxForm handler is not added any more and even if the new values that will try to be saved are ok, the detail view is loaded in another page.
Unfortunately, the use of ajaxForm creates some other problems because I don't have control over the cases when the ajax call fails.
Any ideas on how could I fix this? Is it some other solution to switch between those two views without using ajaxForm and without refreshing the page?
I think there are a couple of different questions that you are asking.
First off, you add jquery handlers to deal with the case when you get a 500 type error from the server.
Something like the following. I suggest taking a look at the docs for more info.
$(document).ajaxError(function(event,jqXHR,ajaxSettings,thrownError){
if (jqXHR.status != 0){
window.location = <error page>
}
}
The second problem seems to stem around error handling of known errors (say invalid input). In this case I suggest the following workflow.
1) User clicks on edit button, taken to edit screen
2) User enters in data, use client side validation to do initial check
3) User submits, user is then taken to the view screen and is shown a
success or error message.
The server response could look like:
public ActionResult Edit(EditModel model){
if (!ModelState.IsValid)
{
return Json(new {successful = false, message = "Failed.."});
}
...
}
On the client side, your form callback should now handle the message and the fact it was successful or not. In my implementation, I used knockoutjs to create a "message" area that I could update and clear. (I created templates, etc).
Remember to use client side validation for the easy field validation stuff.... This will save a trip back to the server.
Yours could be quite simple, by popping up the message returned from the server.
Lastly, document ready only fires when the original document is done loading, never again for an ajax call (at least that is my understanding). Just put that code that is the document.ready at the bottom of the edit page. It will fire after the html it is targeting has already been rendered.
Hope that helps!
I have begun to move away from the asp.net views available in ASP.Net MVC due to some incompatibilities and/or unnecessary complexities when trying to achieve functionalities expected of AJAX enabled sites of the day.
I would recommend moving towards a design where you use "dumb" HTML files, use jQuery to download them using AJAX and drop them into a container (personally I use a div) and then use another AJAX call to gather the data from a controller. There are a number of advantages to this approach:
It establishes a real (not fake) separation between client side and server side code.
Html files can be cached on the client cutting down on the amount of data transmitted.
Binding of the Html elements becomes a client side task achieved using jQuery offloading processing cycles from the server.
Controllers essentially become collections of web methods which means they can be untilized by iPhone and Android apps making mobile deployment easier.
I realize this probably isn't the exact answer you're looking for and this may not be an option for you but my hope is that it will help someone at some point make a decision to move away from mixing HTML and server side code.

ASP.Net, Drag-n-Drop, Postbacks, and Control IDs

The title attempts to summarize the problem, but here's a more detailed summary: our web page is a collection of usercontrols, which visually render as rectangular reporting widgets, which are set in AJAX updatepanels. We are giving the user the ability to drag and drop the widgets to pre-set "zones" on the page.
The drag and drop functionality works fine. We use AJAX calls to a web service to update a database with the user's new settings for persistence.
The "however" happens when we do a postback from one of these widgets. The postback is sent to the server, it renders an update, which is sent back to the client (all via AJAX, because of the updatepanel). We then get a "Could not find UpdatePanel with ID..." message on the client, because the document hierarchy has changed, but the control IDs have not been updated on the client.
We tried Rick Strahl's solution to this link text, which allowed us to create static control IDs on the client. This breaks the postback functionality, though... the isPostBack property is not set, I'm assuming because the server can't match the control ID with a known hierarchy element.
We're thinking about possibly resetting the control ID on the client side after it's dragged and dropped, using Javascript. Obviously, this would require duplicating .Net's naming algorithm--not smart, we're thinking. Maybe we can use a separate updatepanel and ask the server to send us the new control ID after it's dropped?
Obviously, we're running out of ideas.
I realize this is probably too long, and I'll happily edit, provide code samples, etc. to help you help us. Thank you in advance.
Just out of interest, have you inspected the id of the UpdatePanel that posts back, and is the id one that is expected? You can hook into the client page lifecycle of ASP.NET AJAX like so to inspect the id of the control initiating the postback
<script type="text/javascript">
function pageLoad(sender, args)
{
var prm = Sys.WebForms.PageRequestManager.getInstance();
prm.add_initializeRequest(InitializeRequest);
prm.add_endRequest(EndRequest);
//fires when an async postback is initialized
function InitializeRequest(sender, args)
{
alert(args._postBackElement.id)
}
//fires when an async postback is complete
function EndRequest(sender, args)
{
alert(sender._postBackSettings.sourceElement.id)
}
}
</script>
You could use ASp.Net's built in system for draggable page elements called WebParts.
The system works with postbacks and can be easily implemented with Visual Studio
Have a search for webparts tutorials such as:
http://www.ondotnet.com/pub/a/dotnet/2005/01/10/liberty.html
Hope this helps

Categories