scrollTo Paging called too fast - c#

I am using the scrollTop function to detect how close a user is from the bottom of the screen to add more content. My javascript function is like this:
if ($(window).scrollTop() >= $(document).height() - $(window).height() - 75) {
var url = '<%=Url.Action("MoreView", "Status", new { id = ViewData["Id"],
page = Convert.ToInt32(ViewData["PageNumber"])+1 })%>';
NextPage(url); //this does an ajax call to the action method on the server
}
Everything is working fine, the problem is that the window.ScrollTop >75 is happeng sometimes 2 or 3 times so fast that it loads the same content 2 or 3 times. I can probably fix this by using a session variable on the server side but didn't want to go that route because that can get ugly IMO. Any suggestions?

As it stands right now you will always be making a request to the same URL (resulting in the same data every time, unless I mis-understand what you are doing). Once you fix that, you'll probably want to wrap your function that is called when the user scrolls in a debounce function (I'm using Underscore.js' debounce function for this example):
// Only call yourOnScroll once it hasn't been called
// for more than 100 milliseconds
yourOnScroll = _.debounce(youOnScroll, 100);

Related

How to update status in db on webpage leave/closed?

I want to update status flag 1 if user working on say 'XYZ' page and immediately update 0 when user leaves this page
i can able to update flag 1 by simple update query with linq in respective controller when user enters in.
but the problem is how to update flag 0 when user leaves or closes browser window directly
i tried adding following code :
window.onload = function () {
window.addEventListener("beforeunload", function (e) {
----------AJAX FUNCTION TO UPDATE DATA HERE--------------
});
};
But the problem is how to get callback of this alert-box
see the image here
You can't be certain that this will work consistently just by using clientside functionality, as there could be many ways a session ends, which would NOT be caught by this. Examples could be:
losing internet connection
losing power
server endpoint being down
If you want consistency in this, you have to back it up with something server-side, that "expires" sessions that have not been heard from in x minutes.
So my suggestion:
Set flag to 1 when user enters page.
Implement the code you already have to update flag to 0.
Run a server function (using hangfire for background jobs could be an option) and update all sessions with flag 1 to 0 when it has not been active for x minutes.

Jquery wait till a function with ajax call in loop is completed - Refresh after a Button Click

I have some code inside a button click event in jquery. It gets all the radio buttons in a aspx page and it will loop through them according to their clicked status and save them using ajax call (to a function in c# which indeed passes it again to a webservice) one by one.
Now I want to call page refresh function after the saving event. But when I call the event the page is getting refreshed before all the saving could happen and only few of the clicked button are in their new checked status while others are still loaded according to their old status.
So how do i wait till all the saving is done and call the refresh function... I tried jquery when and trigger and few other methods but nothing seem to work..
$('#btnsubmit').click(function() {
$('.radioControl:radio:checked').each(function(e, i) {
.............
commentsAjax.doAjax(...); //function
});
refresh();
});
commentsAjax = {
doAjax: function(....) {
................
some function call in C# code which from then goes to a web service
success: function(e) {
//alert('Saved Successfully');
}
};
You're going to have to use a concept of recursion, or loops with a callback basically.
(function recur(elements) {
var elem = Array.prototype.shift.call(elements);
if(elem) {
$.ajax({
url: "/path/to/check",
success: function() {
recur(elements); //Success, go again
}
});
} else {
//Done!
refresh();
}
})($(".radioControl:radio:checked"));
What's happening here is that we first create our recur function. You might be familiar with the IIFE (Immediately Invoked Function Expression) pattern where we create an anonymous function and invoke it immediately ((function(){})()) however in this case, we name it which thus allows us to call said function within it's scope whenever we want to progress in the loop. Next, we send an array of elements and as we slowly progress through the loop, we shift the first item out of the array and send the new, shifted array into the next iteration. This depletes the array until were left with no elements, i.e. finished!
The reason we use Array.prototype.shift.call is because a jQuery object is not a native array but has all the necessary elements to allow us to call the native shift function on it (which are length and the ability to access objects at indexes).

Detecting if a user has left the site [duplicate]

This question already has answers here:
Warn user before leaving web page with unsaved changes
(17 answers)
Closed 9 years ago.
I am currently working on a website in aspx, where I need to detect and record if a user is about to leave the site.
It will need to capture if possible all of the following, if the user:
clicks on the browser Back or Forward buttons
clicks on the browser close button
clicks on the tab close button
navigates to a new website
If it's remotely possible, change the requirement, because it will lead to a less-than-ideal user experience.
On at least some browsers, you can do a synchronous ajax request from the onbeforeunload handler to send information to your server that the user is leaving the page:
window.onbeforeunload = function() {
$.ajax({
url: "/path/to/page",
data: {/* ...stuff... */,
async: false // <== Option is being removed soon
});
};
The reason I say it's a bad user experience is that since the ajax call is synchronous, it holds them up, and fairly intrusively on some browsers (the whole thing locks up while waiting for the request to complete). This is also why it may well not be reliable cross-browser.
The jQuery team is removing the async option from ajax at some point. It's still there in the underlying XMLHttpRequest object, so when that happens you can use that directly.
The fact the user left the site is already apparent from the web server logs, although you can't tell how long they spent on the final page. If that "how long did they spend on the final page" is really vital information, rather than holding them up when they leave (and relying on something that may not be entirely reliable cross-browser), you could use a background "ping" while they're still on the page. It would probably be best to do the pings further and further apart over time.
So for instance, when the page loads:
(function($) {
var SECOND = 1000;
var MINUTE = 60000;
var arrived = +new Date();
var pingTimes = {
0: 10 * SECOND, // Every 10 seconds in first minute
1: 30 * SECOND, // Every 30 seconds in second minute
2: 45 * SECOND, // Every 45 seconds in third minute
other: 60 * SECOND, // Every minute otherwise
long: 10 * MINUTE // Every 10 minutes if they've been here a long time
};
nextPing();
function ping() {
$.ajax({
url: "/path/to/ping/page",
method: "POST",
success: nextPing,
error: nextPing
});
}
function nextPing() {
var elapsed, pingTime;
// Get the # of full minutes they've been here
elapsed = Math.floor((new Date() - arrived) / MINUTE);
// If it's been a long time, use `pingTimes.long`.
// Otherwise, use the time from the table or the default.
pingTime = elapsed > 15 * MINUTE ? pingTimes.long : (pingTimes[elapsed] || pingTimes.other);
setTimeout(ping, pingTime);
}
})(jQuery);

Update MVC 2 view every few seconds

I am using MVC 2, I have view which simply displays label with current time on it.
I want to update this View(label) every 5 seconds so time will update. I am using below (taken from here) but doesn't seem to be working.
public ActionResult Time()
{
var waitHandle = new AutoResetEvent(false);
ThreadPool.RegisterWaitForSingleObject(
waitHandle,
// Method to execute
(state, timeout) =>
{
// TODO: implement the functionality you want to be executed
// on every 5 seconds here
// Important Remark: This method runs on a worker thread drawn
// from the thread pool which is also used to service requests
// so make sure that this method returns as fast as possible or
// you will be jeopardizing worker threads which could be catastrophic
// in a web application. Make sure you don't sleep here and if you were
// to perform some I/O intensive operation make sure you use asynchronous
// API and IO completion ports for increased scalability
ViewData["Time"] = "Current time is: " + DateTime.Now.ToLongTimeString();
},
// optional state object to pass to the method
null,
// Execute the method after 5 seconds
TimeSpan.FromSeconds(5),
// Set this to false to execute it repeatedly every 5 seconds
false
);
return View();
}
Thanks for help in advance!
What you are doing won't work as once the initial response is sent to the client, the client will no longer be listening for data from your server for that request. What you want to do is have the client initiate a new request every 5 seconds, then simply return the data for each request. One way to do this is with a refresh header.
public ActionResult Time()
{
this.HttpContext.Response.AddHeader( "refresh", "5; url=" + Url.Action("time") );
return View();
}
You need to put your recurring loop on the client side so that it reloads the page every five seconds.
One way, using Javascript:
<script>setTimeout("window.location.reload();",5000);</script>
The code you provided, runs at server, and when a page (View in this case) is sent to the client, the server will forgot it! You should create a client side code for refreshing the page every 5 seconds. You can use a header command (refresh) or a script:
<script>
setTimeout("window.location.reload();", /* time you want to refresh in milliseconds */ 5000);
</script>
But if you just want to refresh the page for updating the Time, I never suggest you to refresh page completely. Instead, you can create a javascript function, to tick every 5 seconds, and calculate the current time and update the label.

What's the correct way of posting this data asynchronously, and canceling/queuing new requests?

I am attempting to improve the stability of the web dashboard I have created. I have noticed that the main cause of getting into a bad state is when the user moves too quickly and requests get cut short.
For instance, I have the following javascript:
//When a resize occurs a lot of handling needs to happen to convert the user's action into
//a visibly-pleasing result. In addition, the server has to be spoken with in order to save the controls.
function OnClientResizing(pane, eventArgs) {
eventArgs.set_cancel(true);
var parameters = new Array();
parameters.push("Resize");
parameters.push(pane.get_id());
parameters.push(eventArgs.get_delta());
__doPostBack(pane.get_splitter()._uniqueID, parameters);
}
This function passes the hard work back to the server, so that it can calculate the appropriate ways to resize the controls on the page during resizes. This takes X seconds. If the user then resizes the page again before X seconds has elapsed -- I enter into a bad state. Either the old request gets cut off prematurely, or the new one runs at the same time. Either way, controls become mishapen on the page.
As such, I would like to queue future resizes, or play around with canceling current requests. I read that the best way to do something like this is to simply set a flag outside the scope of this function. I can do that, but I am not sure how to detect the end of a doPostBack. Am I supposed to change the javascript variable from the server-side somehow in PageRequestManager - EndRequest?
Cheers
First off, don't let your server participate in UI resize algorithms. Do that entirely client side. You can send resulting data to the server at any time, but don't make a real-time UI positioning depend upon a server response. That should be handled client-side with CSS or javascript logic.
Second off, if your code can't handle two ajax calls in flight at the same time, then your options are as follows:
Fix your code so it can handle sequential ajax responses in flight at the same time.
Cancel/ignore the first ajax response the moment you send a second one so that you ignore the response from the first and wait for the response from the second.
Prevent a second ajax request until the first one completes. I wouldn't suggest queueing them because that's just going to lead to an even worse user experience.
The details of how to do 1, 2 or 3 depend upon how your code works which you have not yet shared.
The easiest is option 3). That can be done with just a global flag. Just define a global variable, set it to true when you start an ajax call and clear it when the ajax call completes (in a completion function):
var ajaxInFlight = false; // global declaration
function OnClientResizing(pane, eventArgs) {
if (ajaxInFlight) return; // do nothing if ajax call already in flight
ajaxInFlight = true;
eventArgs.set_cancel(true);
var parameters = new Array();
parameters.push("Resize");
parameters.push(pane.get_id());
parameters.push(eventArgs.get_delta());
__doPostBack(pane.get_splitter()._uniqueID, parameters);
}
function postBackCompletionHandler(id, parms) {
ajaxInFlight = false; // clear global flag, ajax call done
// ... rest of your function here
}
You will also have to make sure that error conditions are handled so that the global flag is reset if the ajax call fails for any reason.

Categories