A page presents a dialog with an OK button. Under certain circumstances clicking the OK button fires its click-handler twice (event.timeStamp is identical). Invoking event.stopPropagation() in the click handler did not make the problem go away.
I've 'fixed' the problem by comparing event.timeStamp with its previous value. That is not a very satisfactory fix. What else might do the job?
The Circumstances
This problem follows relatively minor changes to code that has been running, and evolving, over years. There is a lot of it, and it would be difficult to pare the thing down to a few lines for illustration. The changes involved adding a dialog to load tide data for a year other than the current year. FWIW here's a very brief summary of how the page works.
On opening, it sends a GET request for a year's worth of tidal current data. Subsequently, a method increments a time, draws a field of vectors appropriate for that time over a NOAA chart, and schedules itself to run after a few seconds. It iterates in that manner over a time-frame.
The user can define a course, run a vessel along it, and see how current affects its track. The course definition, which includes a launch time, can be saved (as a cookie) and restored. If, when attempting to restore a course, available current data don't bracket the launch time, a warning is given and the dialog closes without changing the state of the page.
The user can then open a second dialog to GET the appropriate tide data. They can then try again to restore the course. This dialog changes the tide data and parameters describing the time and time-frame.
The problem - two responses to a single click - occurs only when an attempt to load a course fails, a new dataset is loaded, and a second attempt to load a course is initiated.
On that second attempt, code handling a click on the OK button of the load-the-course dialog gets the same Click event twice. I conclude it is the "same event" because the timeStamp value is the same. Oddly, the
If the tide data are loaded first, and then the course retrieved, the problem does not arise.
I'm not optimistic about an answer; a detailed description would be impossibly long. Constructive suggestions welcome. (event.preventDefault() does not change the behavior. Did not expect it to, but Due Diligence and all that.)
Related
I'm working with a web page that has a tabbed display that simply hides all but the selected tab using the display style property. When a new tab is selected, a function is called that gathers some data from the page and writes it to an indexedDB object store to be used to restore the previous state of the tab, such as the selected element and cursor position, none of which seems efficient to save at every individual change.
At the same time, the important data is saved right away, such as a change event on a textarea, which will write data to the same object store as above.
My question is what should take place when the user writes new text to one of the textarea elements and, while the textarea still has the focus, clicks a button to navigate away from the tab (not the browser tab but just the tabbed display within the web page)? This single user action triggers two database write transactions at the "same" time and on the same object store.
In testing, I have tried to place a large amount of data in the textarea, before navigating away from that tab, in attempt at causing the change write event to take more time to complete; but, the write transaction triggered by the change event always completes before the event capturing the last state of the tab.
A reason for this may be that, apart from the last scroll position, all the data is taken from the dataset object of a small number of HTML elements, and that step may take longer before the transaction is even opened.
However, I'd like to feel more confident that this is coded as close to "fail proof" as possible, and would like to know how to prevent these two transactions from ever blocking or interfering in any way causing the loss of data or program failure.
I don't really know what to provide for a code example because there is nothing to show but a textarea element with a change event and a set of radio buttons, also with a change event, that invokes a function to gather data and open a write transaction before hiding one tab and showing the other.
Everything works and has not failed once yet, but how can I code it to be certain?
Thank you.
Addition After agonizing over this for awhile, I think I misunderstood the concept of blocking in indexedDB. I just assumed it had to do with two write transactions attempting to write to the same object store at the same time, but after reading further I don't think that is the case. If I understand correctly, this MDN document states that transactions are processed in the order they appear in the code, and the example is of two write transactions.
Thus, for my question of a change event triggering a write transaction at the "same" time as another write transaction is triggered, it would appear the only concern would be that one transaction overwrites the data written by the other transaction. The browser will handle the rest and I don't have to worry about transactions interfering or blocking, apart from their order when important. Blocking appears to be version change concern on an open database.
Regarding my original question, the change event always completed first in testing because its transaction was always opened first since it fires, I assume, on a blur event on the textarea which takes place before the change event on the radio buttons which fires on mouseup triggering the second write transaction. I assume that the second write transaction opened on the same object store won't begin until the first completes; but there isn't that level of description in the referenced document apart from below.
After the code is executed the object store should contain the value "2", since trans2 should run after trans1.
The point being that even if the first write transaction takes considerably longer relative to the second, the second will not start until after the first completes, and the only concern is the second transaction potentially overwriting data written in the first.
Sometimes I get myself confused and make issues where there aren't any and the coders of the browser have already taken care of it.
If I am still misunderstanding, I'd appreciate being corrected. Thank you.
I am a lowly operations employee without authorization to change the programs and permissions on my machine, and I would like to automate some highly repetitive data entry. I know there are a lot of programs that can do that, however, for the sake of this discussion we'll assume that I'm not allowed to have any of them and I can only script through the debug F12 menu in Chrome. I also probably don't understand half of these words as well as I should.
I have to run test cases on a third-party vendor's highly dynamic website, and I've already successfully written javascript which adds texts to elements in the DOM and presses the "next" button.
The problem is, upon .click()ing the "next" button, it takes time for the page to update, and the update creates new elements which weren't in the DOM when the script was initialized. I need to find a way to delay the execution of the script until the DOM contains all the elements I need to update.
As a really, really crude proof of concept I wrote the pre-filler for each page as a function, and I serially called each function at the end of the previous function, using setTimeout(nextfunct, 10000) to let the page update before executing the next line. (I was going to refine that by trying to create some kind of object listener instead of an arbitrary 10 second delay, but I wasn't even able to get that far.) This approach creates two errors.
1) The script seems to be checking whether the elements are on the DOM before the end of the setTimeout(), so it still gives me an error. If nextfunct is defined as
document.getElementById("doesntexistyet").value = "Fill Me";
console.log("nextfunct ran");
I will get the error message stating there is no element with the id "doesntexistyet" immediately, not after a delay of 10 seconds. The element on the next page will not update.
2) The DOM updating interrupts my script. In the above code, the console output will not ever appear in my console. If I comment out the missing element, so the function only prints a comment, it will still not appear in my console. However, if I comment out the code and I switch the setTimeout to 1ms, "nextfunct ran" will appear in my console, until the page updates, at which time the console will be deleted.
Are there ways around this which I can implement using only vanilla JS and a browser? I'm sure there's a keyword I can search for where someone has discussed this before, but it seems like the vast majority of JS autofilling discussions are oriented towards people designing code to be integrated into a website,
Thanks
I want to put some logic before user leaves a page, but I want to handle reload button & close button action differently.
All I know is that there is onbeforeunload event that will be called before user unload the page, but it doesn't solve my use case.
I want to create some statistic/tracker, something like this:
$(window).beforeunload(function() {
if (user click browser's close button)
// track_user_click_close_button()
else if (user click browser's reload button)
// track_user_click_reload_button()
});
You can't know the URL user will be navigating to. This is not a jquery/js issue.
The bottomline is - you cannot do what you want.
Update
But if you try sometimes, you might find - you get what you need.
As stated in this SO answer to a similar question, there is something you can do to overcome this inability. I strongly suggest you to read the described approach.
If it's not suiting your needs, please open a new SO question with detailed explanation of what you're trying to do, and we'll try to help you.
Another update
Unfortunately, there's no way of determining this out-of-the-box. You can try the following approach:
$(window).beforeunload(function() {
// should be a synchronous AJAX-call, as async one won't work
persistLeaveOnServer();
});
$.ready(function() {
tellServerWeAreBack();
});
And on server side you should maintain the session state according to that. Once certain amount of time has passed (probably, several seconds), you consider the session ended and persist the statistics as UserClickClose. If tellServerWeAreBack request is received before this time passed, you save UserClickRefresh stat value.
beforeunload fires whenever the user leaves the page. If you want to differentiante between a refresh and a close you must be able to detect the page reload.
You could keep an information telling the page that it is unloading at xx:xx time. Log the fact to some place. When the page is loaded, check whether there is some logged evidence that the page was quit recently (depending on your definition of recently) and turn the event into a refresh event: (see here for an example)
This may not be able to differentiate between a refresh and a user closing then reopening the page quickly (under your time treshold).
Note: the linked page mentions using hidden form elements that are persisted between refresh, but says that browser support is all over the place; I'm wondering if this is still the case or not. Storing information in the window object will survive refreshes so you may want to explore this avenue
I am sure others have encountered this problem before, but this is doing my head in.
I have a page that generates a list of products. It's a long list so may go over several pages. I have Back and Next buttons to achieve this and they work if the user stays with the list.
The problem occurs when the user selects a product from the list and navigates away to a new page to display more details on the product. When the user has finished with this page and exits, the list of products is redisplayed at the point at which the user left it.
In chrome, the popstate is fired, and I have to adjust the number of go-backs required (due to pushStates I have already performed) on the next popstate in order to get the back button to then go to the correct previous page. In firefox, the page is being restored from the cache, and I am not being given the chance to intercept the return and make the necessary adjustments.
Is there some way to force Firefox to clear the cache and trigger the popstate when the back button or exit button is selected from the product detail page?
I've used this jQuery code before, and it works cross-platform:
$(window).bind('popstate', jQuery.proxy(function() {
// your code here
}, this));
The code inside the callback will run anytime the user presses the back button.
It's unlikely to be easy to force Firefox to clear its cache for security reasons. Here's one tip I found that might work (untested by me). But hopefully you can use this callback to do something else that's useful, like setting your navigation state correctly.
You might be able to find more useful information here.
I think you need a window.onunload handler. See https://developer.mozilla.org/en-US/docs/Using_Firefox_1.5_caching which talks about the introduction of bfcache.
I'm working on a web app in ASP.NET 2.0 that involves several GridView elements. When users click one of the rows in a grid, that row needs to show its selection by changing color. Each row has attributes set to identify its record type and unique ID:
<tr data-elementType='myType' data-myID='12' onclick='selectionFunction();'></tr>
I accomplish the selection through a javascript onclick handler on each row that calls a function that:
Removes the selected class from the previously selected row
Adds the selected class to the new selected row
Updates the value of a hidden field with the new selected unique ID so server-side code can know which element to perform an action on when a button is clicked (view, delete, etc).
One of these grids now has just over 700 records in it. In Firefox 3.6, the selection operation on this grid is horribly slow (about two seconds); in other browsers (even IE 7 and 8) it's not a problem. I put console.log statements at the start and end of the selection function, and in Firebug they show up very fast at the end of the delay, suggesting that it's not the selection function that is slowing things down. I used the profiler in Firebug and it says that "createCallback", which is defined in one of the "ScriptResource" script files generated by ASP.NET, is taking the huge majority of the time. What is createCallback and why does it seem to be so slow in Firefox 3.6? Is it a bug in FF, or is it a problem I can solve?
UPDATE: I am, of course, using jQuery to add/remove classes from the rows. I've been working with jQuery 1.5.2 and jQueryUI 1.8.11, but I updated to the latest (1.6.2 and 1.8.14 currently) to no avail. I tried putting a breakpoint in createCallback to see where it's getting called, and when it breaks there it's several frames down in the call stack from my call to removeClass. Here is what the stack looks like in Firebug:
createCallback() - in ScriptResource.axd?......
wherever possible trim: trim ? function(text=" ") - in jQuery
removeClass(value="selectedRow") - in jQuery
removeClass(classNames="selectedRow", speed=undefined, easing=undefined, callback=undefined) - in jQueryUI
selectionFunction() - in my .aspx page
onclick
I don't understand why jQuery is triggering an ASP.NET generated function like this.
UPDATE 2: some more investigation has provided some more detail. It seems that this "createCallback" function is getting called A LOT when I use addClass/removeClass, and it's happening in both Firefox 3.6 and Firefox 5. I found the same function in Chrome and put a breakpoint on it, and it's not getting called at all, so this seems to be a Firefox thing. I put a breakpoint on the function/line in question and selected a row, and the breakpoint got it 57 times. Only the first two involved me calling removeClass and addClass; the rest had createCallback several times in the callstack, and sometimes BeginRequestEventArgs too. I've noticed it getting called also when I mouseover other jQueryUI stuff on the page (tabs), when jQuery uses addClass and removeClass. But why is it getting called so many times when I do work on tr elements?
I'm changing the title and tags to reflect the real issue.
UPDATE 3: createCallback is getting called about the same number of times whenever I select a row in any of the grids, even if it only has 6 rows in it. But in that case it's not a performance problem, and the profiler shows it only taking about 30% of the execution time, while it's at least 80% when I profile selection on the larger table. So createCallback seems to perform worse when it's used in the context of more stuff visible on the page. But it still seems like jQuery shouldn't cause a call to createCallback, especially since I couldn't fine any references at all to it in Firebug's script search. And it appears to only get called in Firefox!
Note also that all of these grids are on the same page, but only one is visible at once, because I'm using jQueryUI tabs.
UPDATE 4: I managed to get something similar up on jsFiddle as requested. See here. In Firebug, find createCallback and set a breakpoint (just below my click handler in the script, where it begins with Function.__typeName = "Function"; Function.__class = true; Function.createCallback = function (b, a) and reload the page. I get a lot of calls to it.
I have very little knowledge of ASP however it sounds like your problem is purely client side.
Declaring on "onclick" event for each row is not the most sensible way to handle the rows being clicked. Especially when you get into the quantity of rows you're talking about (~700+).
A better way would be to add a click event handler to the table and figure out what is clicked when it happens. I have written an application where a similar size table is being handled and we're not seeing anything like the lag you're experiencing upon click. there may well be other factors causing your click events to slow down however I would still suggest something along the following lines is worth implementing in any case:
$(function(){
var rowSelectedClass = 'rowSelectedClass';
$('#myTableID').click(function(e){
if(e.target.nodeName === 'TD'){
var $tr = $(e.target).parent();
$('tr.' + rowSelectedClass).removeClass(rowSelectedClass);
$tr.addClass(rowSelectedClass);
// ....
// Do whatever else you want to do when the row is clicked
// ....
}
});
}
A good article to take a look at which advocates this method (and a few other handy jQuery tips) can be found here: http://www.artzstudio.com/2009/04/jquery-performance-rules/#leverage-event-delegation
Also worth noting that if your table has rows added dynamically after the page is loaded then consider using .live() instead of .click().
UPDATE # July 28th 2011 9AM
Having taken a look at the source more closely, I think the supposed calls to "createCallback" are a red herring. The line within your original jsFiddle source which contains the "createCallback" function is actually a really long string (~90,000 characters) of javascript. I think the fact that "createCallback" is the first function within that string is misleading Firebug's profiler. When you profile your original page's load, there are 2261 calls and as you said, there appear to be lots to "createCallback"
I've "beautified" (hate that phrase) this long JS string via http://jsbeautifier.org/ to make it readable and re-added it to a jsFiddle page. You can see it here: http://fiddle.jshell.net/KvpmE/1/show/. Now when you profile this page's load you'll see a similar number of calls (2267 - not sure what happened to the other 6!) but importantly not a single one to "createCallback".
I still can't offer any solution though because essentially I've been unable to re-create your original issue which was that there was a 2 second lag in Firefox 3.6 when clicking a row.
Is this still the problem you're having?
Could you try and see whether you can re-create the problem within the updated jsFiddle page?
Also try and add the de-minified JS to your page to see if it helps you track down the actual functions being called when the row is clicked and therefore where the lag is taking place.
Mr. Jefferson,
It really sounds to me like you're actually performing a postback without knowing it. Have you set a breakpoint on the server side yet to see if something is inadvertently firing your update panel? It really sounds like some kind of postback is happening that is requiring a reload of dependant scripts.
I say this because 1) the problem you're having makes absolutely no sense - you're 100% on the money with JQuery and the ASP.NET Client Framework not even knowing they're neighbors in this case, and 2) the BeginRequestEventArgs instantiation sounds like the PageRequestManager thinks it should be doing something in response to your triggers... You could also try breaking out Fiddler and just doing a quick sanity check to make sure some update panel of yours isn't firing. There should be no HTTP traffic during the ops you're describing.
Sorry if this is an absolutely useless post for you, but with all of the work you've gone through to troubleshoot the client side it can't hurt to set a server side breakpoint just to do a quick sanity check / occam's razor...
Good luck - happy coding.
B
Function.createCallback is used a lot internally by Ajax Toolkit and maybe its being called within your code unintentionally too http://msdn.microsoft.com/en-us/library/dd409287.aspx.
Since this is browser dependent, I would check code paths that are executed based on a specific browser.
Another clue to look for is if you're having any Ajaxtoolkit components for the grid or its individual rows as that would explain the increase in number of calls with the increase in rows.
There is also Type.createCallback function (http://msdn.microsoft.com/en-us/library/bb397568.aspx) so if you have any Type related code or methods, I would check those.