jQuery .load seems to be running at an unexpected point - c#

So I'm trying to load some returned html from an .aspx page but a click event needs to fire before it doing some stuff that the AJAX request depends upon. More specifically, I'm doing this. When a user types in a text field this function is run...
function KeyPress() {
$("#" + HiddenButtonId).click();
$("#test").load("TempJumpToAJAX.aspx");
}
then $("#" + HiddenButtonId).click(); does sets some session data in a code behind file. Specifically...
Session["SearchText"] = Search.Text;
then, $("#test").load("TempJumpToAJAX.aspx"); calls that .aspx page that returns a newly built select box...
Response.Expires = -1;
StringBuilder builder = new StringBuilder();
builder.Append("<select id=\"testListId\" name=\"testList\" size=\"4\" style=\"width:200px;\">");
builder.Append("<option>");
builder.Append(Session["SearchText"]);
builder.Append("</option>");
builder.Append("</select>");
Response.ContentType = "text/HTML";
Response.Write(builder.ToString());
Response.End();
The problem is, the order seems to be screwed up it tries to append the Session["SearchText"] first, then runs the code that the click event runs. So it functions more like this...
function KeyPress() {
$("#test").load("TempJumpToAJAX.aspx");
$("#" + HiddenButtonId).click();
}
Where the commands are reversed. So what in effect happens is the session variable has an empty string as opposed to what the user typed in the text box. What's odd to me is that it doesn't seem like it should have an empty string, it seems like it should have nothing since the session variable has not been initialized to anything at this point. I really have no idea what's happening. Chalk it up to inexperience I guess. Any ideas?

You are mixing technologies here. The hiddenButtonID click event is trying to do a full postback for the page, whereas the AJAX call will not do a postback. There is no reason to do a post back and then follow it up with an AJAX call. The point of AJAX is to eliminate the need to postback the page and instead just reload a small amount of the HTML on the page using a small callback to the server. Instead of accessing the Search Textbox text in the HiddenButtonID click event handler you should be passing that data to the Server in the AJAX call parameters.
The following client side script should do this.
function KeyPress() {
$("#test").load("TempJumpToAJAX.aspx", {searchText: $("#").val()});
}
In this code you are getting the ID of the search textbox and then using jQuery to retrieve the value of that text box. This will get passed to the TempJumpToAJAX.aspx page as POST variable called 'searchText'. You should be able access this data by accessing the Request['searchText'] variable in the 'TempJumpToAJAX.aspx' page.

Another smart extension to what you are doing, is not to do the ajax call as soon as a key is pressed. If the user types in a long word quickly, you'll get multiple ajax http requests triggered faster than they can return and update your UI.
This adds to your server load, and might make the client's UI sluggish.
Instead, onkeypress, store all the appropriate details and then call
var timeout = setTimeout('some_method()',100);
Which says call the some_method() in 100 milliseconds. The first thing you should do within your keypress method is cancel/clear the Timeout call with clearTimeout.
http://www.w3schools.com/js/js_timing.asp
The some_method() should also clear any timeout, then make the http ajax request.
The net effect here is that your ajax request is delayed slightly, but never happens if the user presses another key. Or put another way, don't try and fire an ajx request until the user has stopped/paused typing. 100 milliseconds might be too high or too low, but you hopefully get the idea!
You should also take care to deal with a "slow server" situation. Consider this:
User types "hello", pauses for 1 second, you fire an ajax request with "hello" as the parameter
User continues to type " world", so the textfield now contains "hello world", and stops typing.
You fire a second ajax request with "hello world" as the parameter.
The second request (for "hello world") returns first, you update your UI
The first request (for "hello") returns, you update your UI again.
Ooops! Have the server include the original query string in the (json) data it returns to the client. When the client gets the ajax data back, check that the result/data is for the query ("hello" / "hello world") that matches what is currently in the text field.

There is a JQuery plugin that encapsulates what the previous answer is talking about. Its called TypeWatch. It allows a function to fire once the user has stopped typing in a text field for a specified number of milliseconds. I've used it before and it works quite well.

Awesome! Thanks to everyone all your answers were quite insightful. The real issue I learned was that I did not know how to send variables with that ajax request. This here.
$("#test").load("TempJumpToAJAX.aspx", {searchText: $("#").val()});
Also mintywalker, thanks for the insight. It was all good.

Related

Using await in async methods to prevent next line of code from running

I'm new to using async methods, so I think I'm misunderstanding something. I have a WinForms app with a button, and when the button is clicked, an async method gets called. This must be async, as I need to make javascript calls to a Chromium Web Browser control (using CefSharp). I need to ensure that this javascript has finished running and that the browser has updated before continuing with the next part of the method.
I'm basically trying to capture the entire web page into a single image. My approach was to use javascript to update the scroll position on the page, then take screenshots in each position using Graphics.CopyFromScreen. This mostly works, however occasionally the resulting image will have the wrong 'chunk' of webpage (e.g., the first bitmap is repeated twice). Here is my code:
// Calculate screen sizes, screenshot spacing etc.
for (int i = 0; i < screenshotCount; i++)
{
int scrollSize = i == 0 ? -PageHeight : (int)browserControlHeight;
string script = "(function() { window.scrollBy(0, " + scrollSize.ToString() + ") })();";
await browser.EvaluateScriptAsync(script);
// Take screenshot, add to list of bitmaps
}
// Combine resulting list of bitmaps
If I add the following
await Task.Delay(1000);
after the EvaluateScriptAsync() call, the final image comes out correct every time. I'm working on the assumption that the javascript is being called but doesn't complete before the screenshot begins. If this is the case, even adding a delay may not work (what if the javascript takes longer than a second to run?).
Am I misunderstanding the way that async/await works?
No, the issue is not with await, the issue is that the Task returned from EvaluateScriptAsync is being marked as completed before you're ready to continue. It's going to be marked as completed as soon as the javascript to inform the browser that it should scroll has executed, rather than being marked as completed after the browser has finished re-rendering the screen after being sent the scroll command.

How can I make the beforeunload event fire only when a browser session is exited

Disclaimer - I should note that my JavaScript is pretty weak.
I'm in the process of inserting code into my website so it can cover a scenario when a user exits his browser, he gets prompted with a proverbial 'Are you sure you want to quit?' sort of confirmation messsage.
I'm in the process of trying to implement this piece of JavaScript on my website:
<script language="JavaScript" type0"text/javascript">
var foo = true;
window.onbeforeunload = askBeforeExiting;
function askBeforeExiting() {
if (foo)
return "Are you sure you want to leave this page?";
}
</script>
The code not only throws a confirmation message when attempts to exit a browser are made. However, it also throws the confirmation when a link to another portion of the site is clicked and other related events.
Is there a way to modify this code to just capture the browser closing scenarios only? I get that scenario like killing the browser from the Task Manager or from a powershell command can't be captured. I just want the scenarios in the current user session where they may exit the browser.
I've been looking over various samples across the web and through code references and can't seem to track down exactly what I want to do. Is this even possible?
I've done this before where a page has a form, and I only want to ask the user for confirmation when a change has been made to the form. You could do something similar, where you attach a click event to all links, for example, that would set foo to false. Something like:
var links = document.getElementsByTagName('a');
for(var i = 0, l = links.length; i < l; i++) {
links[i].onclick = function () {
foo = false;
}
}
Edit: There are many other actions you might have to account for, depending upon your site, however with the information given, this should be a good start for you as there is no direct way to accomplish what you are after.

In Watin, how to wait until a form has been processed by the server?

I'm submitting a form to my server via JavaScript in the view, in order to start a server-side job. The view detects that the job has finished by a JavaScript callback being called. The exact details of the JavaScript communication between server and client should be outside of the scope of this problem (I think), but let me know if you need more details. If it helps, I am using the Comet-like SignalR library, rather than standard Ajax.
Now, I want to test this view in Watin (2.1.0). How can I make Watin wait until the server-side job has finished processing? Should I perhaps update an attribute in the view when it detects the job has finished?
Depends how your js and html code looks. It's not that simple. Try to use WaitUntil... methods.
Let's say that after job has finished new div elements with id foo appears. To wait for that use this code:
ie.Div("foo").WaitUntilExists();
But sometimes it's not that simple. Let's say, that after job has finished, the content of the table changes, ie. old rows are removed, and new rows appears. If so:
//Get cell reference
var cell = ie.Table("bar").OwnTableRow(Find.First()).OwnTableCell(Find.First());
var cellRef = cell.GetJavascriptElementReference();
//Change text of that cell using javascript. jQuery could be used if it's used on that page
//If you are 100% sure, that something will change, just assign cell.Text to text. If so, you don't even
//need cellRef
var text = "Dummy text or random or whatever";
ie.RunScript(cellRef + ".childNodes[0].nodeValue = '" + text + "'");
//TODO:
//Do something here to fire ajax request
//Wait until table will be updated, ie. wait until first cell will not contains assigned dummy text.
//This could be done in many ways.
ie.Table("bar").WaitUntil(t => t.OwnTableRow(Find.First()).OwnTableCell(Find.First()).Text != text);
//or just:
//cell.WaitUntil(c => c.Text != text), but maybe it will not work in your case
Anyhow, this is just some tips. It's almost always a pain, so don't show me your actual code ;)

Cannot redirect after HTTP headers have been sent

When I try to redirect to another page through Response.Redirect(URL) am getting the following error:- System.Web.HttpException: Cannot redirect after HTTP headers have been sent.
I wrote one Response.Write("Sometext"); and Response.Flush() before calling redirect Method.
In this case how do we use Response.Redirect(URL)?
I'm executing a Stored procedure through Asynch call. The SP will take almost 3 min to execute. By that time I'll get load balancer timeout error from Server because this application is running in Cloud computer. For avoiding load balancer timeout I'm writing some text to browser (response.write() and Flush() ) .
You need to ensure that you do not write/flush anything before trying to send a HTTP header.
After sending headers there is no proper way to do a redirect as the only things you can do are outputting JavaScript to do the redirect (bad) or sending a 'meta refresh/location' tag which will most likely not be at the correct position (inside HEAD) and thus result in invalid html.
I had the same error and same approach. You might want to try using a javascript instead of directly calling Response.Redirect.
Response.Write("<script type='text/javascript'>");
Response.Write("window.location = '" + url + "'</script>");
Response.Flush();
Worked fine with me however I still need to check it on different browsers.
if (!Response.IsRequestBeingRedirected)
Response.Redirect("~/RMSPlusErrorPage.aspx?ErrorID=" + 100, false);
You can't use Response.Redirect as you've gone past headers and written out "Sometext". You have to check (redirect condition) before you start writing out data to the client or make a META redirect.
If you want one of those pages that shows text and redirects after 5s META is your option.
You won't get this error, if you redirect before the rendering of your page begins (for example when you redirect from the Load or PreRender events of the page).
I see now in your comments, that you would like to redirect after a long-running stored procedure completes. You might have to use a different approach in this case.
You could put for example an AJAX UpdatePanel with a Timer on your page, and the Timer could check in every few seconds whether the stored procedure has completed, and then do the redirection.
This approach also has the advantage, that you can put some "in progress" message on the page, while the procedure is running, so your user would know, that things are still happening.
Try to do the following:
catch (System.Threading.ThreadAbortException)
{
// To Handle HTTP Exception "Cannot redirect after HTTP headers have been sent".
}
catch (Exception e)
{//Here you can put your context.response.redirect("page.aspx");}
In my case, cause of the problem is that loading data in the scroll gridview is taking a long time. And before gridview data is not loaded completely, but I press the redirect button. I get this error.
You can lessen your data get
or
before loading completion prevent to press redirect button

Threading using AJAX

When the user clicks on a link to generate report I make an AJAX call which generates a pdf file in the background.Now the files are huge running upto 10mb or more.So it takes some time.In the mean time the user should be able to navigate other links as if nothing has happened.So I need to implement in such a way that the pdf generation process gets started & user doesn't have to wait for the process to finish.Is this possible?I am using AJAX Pro with c# with dot net framework 2.0
The problem here is that as soon as the AJAX activity begins the browser enters into a hung stage & the user has to wait although he clicks on a different link.
I would probably create a 'queue' or an 'inbox' for the user ...
start your pdf generation routine with a ThreadPool.QueueUserWorkItem (you would also need to modify your generation method to output to their inbox)
then on each http request check that inbox and notify the user of the item ... you can always poll the server on an interval or somthing
Sure, but once the user navigates to another page, the Javascript that is waiting for the Ajax response is no longer running, so that request is lost. You'd have to either find a way to keep that page open (using frames or exclusively Ajaxified navigiation), or find a way to store the response and notify the user of its completion on the next page view. For instance, storing a session variable that indicates that the operation is completed, or storing it in a database with (perhaps) an "unread" boolean value.
You can have asynchronous Ajax call with which you can do other tasks while response objects returns from the Ajax page.
Here is some example, testAjax.aspx is the Ajax page here :
http_request.onreadystatechange = function() { alertContents(http_request); };
http_request.open('GET', 'testAjax.aspx?', true);
http_request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
http_request.send(null);
function alertContents(http_request)
{//debugger;
if (http_request.readyState == 4)
{
if (http_request.status == 200)
{
var vResult;
vResult=http_request.responseText;
//Write your logic after successful Ajax call here.
}
else
{
alert('There was a problem with the request.');
}
}
}

Categories

Resources