HTML onClick VS jQuery mousedown Timing - javascript

I'm working with legacy HTML pages written ~10 years ago. That being said, it should be explicitly known that refactoring old code is not only NOT time effective, but also a risky endeavor.
A legacy webpage has many buttons which activate JavaScript event(s) using the onClick="myFunction()" tag. I've been tasked with interfacing a JavaScript file (which uses jQuery) into these legacy webpages. I've added the JavaScript file in question and jQuery 1.9.1 source and attached them to the legacy HTML pages prior to the closing body tag, ex:
<script src="jquery-1.9.1.min.js"></script>
This JavaScript source file (which uses jQuery) activates a mousedown event on the buttons with the attached class "getStats", ex:
$(document).on('mousedown', '.getStats', function (event) {
//Stuff
});
However, when the jQuery activates, it does NOT perform the redirect the button is supposed to do through the HTML onClick event.
I can't find any information online on how the HTML onClick and jQuery mousedown event timings happen to understand whether or not I'm encountering a race condition. Both the HTML onClick redirect and jQuery mousedown events need to happen, and I can't just simply go back and edit all the legacy HTML onClick events to be done in jQuery either as that would take months of work.
Sample jsFiddle:
https://jsfiddle.net/koa2hsbp/
The jQuery works right off the bat. If you comment out the jQuery mousedown function, then the HTML onClick works. But I have to make it to where both parts activate (preferably jQuery mousedown prior to HTML onClick), without changing the HTML's functionality. (Again, changing the legacy code is a costly endeavor in and of itself.)

Some explanation about events:
mousedown - triggered immediately after mouse button pushed down while focusing element.
mouseup - triggered immediately after mouse button goes up while focusing element
click - triggered when you have consecutive mousedown+mouse up on the same element.
So in your example - you push mouse down and this immediately triggers code which produce alert. Then you release mouse button, but web paged is focused on alert, not on our element as alert window by nature blocks everything else and interrupt javascript. Since there is no mouseup event - there is no click event as well, so legacy code is not invoked.
Try following to prove I am right - push mouse down and hold it. Then click enter button - this will remove alert. Then release mouse button while on top of element. This will trigger click.
Unfortunately it is hard to mix mousedown click and alert in same example. Consider moving jQuery handler to click if you need alerts. That of cause will invoke jQuery after legacy handler.

Related

How to get actual element clicked on instead of Rails unobtrusive javascript form?

I have a small React 16 menu panel that is running in a Rails 6 application. When the panel is open, I want to close it and stop propagation, if the user clicks outside the panel. (I don't want an accidental click outside the menu to take the user to another page.)
The general approach is quite well understood - here's one question that describes it. In brief:
Using native JavaScript (i.e. document.addEventListener('click', callback)) inside of the React component, listen for the click event anywhere.
When that click event fires, check if the element (i.e. event.target) is within the div of the React menu.
If the click was outside of the React menu, close the menu, and call event.preventDefault() and event.stopPropagation() to stop accidental navigation.
This all works fine in my simple test case. (Here's a fiddle, just to prove it works.)
However, it fails in my nested Rails application, if the user clicks on an anchor tag, because Rails's Unobtrusive JavaScript adds listeners to all anchor tags that contain the data-method attribute. The unobtrusive JS then hijacks the event, and injects an HTML form into the body. The target of the click event becomes an input of that new form. You can see the form being dynamically created when I click on a link in the panel here:
This means that the event.target property is the input in this dynamically-injected form, and not the actual a tag the user clicked on.
So my question is: How can I get the actual element the user clicked on, which triggered the creation of the form.
Stuff I've tried/thought of:
Not using data-method. This works for the links in my menu. But then I cannot do POST events like logout, and any links created with Rails's helper methods.
Listening for onmousedown instead of onclick. In this case, the event's target is the correct element, but calling preventDefault() doesn't actually prevent the click.
Using forms inside my menu component instead of anchor tags. This way, I can do a POST for the logout action, without having to use the data-method attribute which introduces the problem described here. And it just works here, since if I click a link in the Rails app, I know it's outside the menu. But it's a hacky workaround, and it doesn't give me flexibility if I want to listen to some other clicks in the future.

Unable to edit javascript in Chrome dev tools

I am attempting to edit some javascript code that is in the html of the page (not an imported js file). I am able to set break points and step through them, but I can not edit the javascript during the execution or before/after execution. I prettified ({}) and un-prettified the files. The code piece is not minified in this section.
Can I do this?
Does it matter that the code is inside an attached event. Ie a click etc.
I am useing jquery obviously.
I could have sworn this used to be a common feature. But it has been over a year since I have done a lot of javascript.
Using chromium / chrome there are several methods to modify the html of an existing document. At devtools
Select Elements tab, right click on the element to modify, select Edit as HTML , make modifications in frame containing element, then click outside of editor frame
Select Sources tab, select Snippets tab, right click and select New , write javascript, to execute in existing window press ▶ at right panel to run javascript in Snippets middle panel in existing window. For example if $("body").on("click", function() {alert(123)}) is added as a Snippet clicking body element should call alert(123). The event should also be listed in Event Listeners at right panel of devtools when inspecting element. Removing the listener may be somewhat more challenging; even if you click remove when hovering over the listener at right panel, as the event is already attached to the element. The simplest method would be to add a namespace to the event $("body").on("click.abcnamespace", handler), then call $("body").off("click.abcnamespace")
Modifying text existing handlers will not automatically affect , or cancel the event handler previously attached to the element. The simplest approach would be to copy and save existing javascript containing event handler, select Elements tab , right click on element that has event listener, select Event Listeners at right panel, when hovering over the window, document or HTMLElement having event attached a button should be displayed that says Remove. Click that button to remove the event listener. You should then be able to modify the saved event listener and add it back to the existing document with modifications being applied

javascript how to determine what is cancelling an event

I have jquery, bootstrap included in a page I'm writing. It's a complex page. The problem I'm having is with Internet Explorer not seeing mousedown event. Chrome and FF both see the event just fine but not IE.
I wrote a test page with the event and it worked just fine in IE. So my question is...
Is there a way through the developer tools to determine what is cancelling an event?
I have a suspicion that one of the many .js files I've included is cancelling the mousedown event and IE isn't seeing it anymore. Chrome and FF does though. So I'm not 100% that it's being cancelled but it's my only guess I can come up with.
Code is really irrelevant since it's all of jquery and bootstrap. However, I am playing with divs that are draggable and resizeable. That's why I need to use jquery. The bootstrap is used because I also have a wysiwyg editor on the page.
Please don't recommend click. I need mousedown. When the mouse is down the border around the draggable and resizeable div turns red and I have some code that selects that div to capture top, left, width, and height as it's being moved and resized.
If click was selected as the event, the user would have to click the div box first then click and hold to move it. That's not a user friendly interface.
Any help is greatly appreciated.
What do you exactly mean as cancel, .preventDefault() or .stopPropagation? If we are talking about preventDefault - you should still be able to add event listener to parent container and then see your event object - it might have some data to traceback. Alternative would to override jQuery .on method and see who actually subscribes to the event.
After little more thinking - add another listener BEFORE the malicious one, to do that insert document-ready handler with event binding right after jquery loading code. In your new mousedown handler try to override problematic method of the event.
UPDATE:
you should try to check all events attached to your element one by one. To do that - check this post jQuery find events handlers registered with an object
In short - try using jQuery._data( elem, "events" ); to see attached event listeners and inspect their code in your code base. After you find the reason it will be much easier to reach the desired functionality. Before that it is just a guesswork.

Events not always firing

I'm not really sure how to go with this, but here goes:
I have form elements that trigger a function (mainly for validation purposes). This triggers on click, on change etc. These are written with vanilla JavaScript.
If it's a straight-forward HTML element then everything works fine. E.g. a element fires on change.
However, if I use a jQuery script (e.g. a jQuery colour selector), then although that jQuery script populates an field, the validation script doesn't fire.
This I suppose is obvious as you don't click, blur, change it, it's just the jQuery script changing it.
Of course I could change the JavaScript in the colour selector jQuery script so it also fires the validation script, but there must be a better way where as well as on click, on change, on blur etc. I can also activate the function when it picks up that another script is changing it. I need this for various occasions and scripts.
Another example is a rating script (rate out of 5). It uses radio buttons as a non-jQuery fallback and the jQuery script just hides those radios (with CSS), displays the star images and then changes the radios when the user interacts with the star images. That way the server handles a form submit the same way regardless of the availability of jQuery. However, the validation script doesn't fire.
Any ideas?
Apparently the elements are being inserted on the dom after the javascript run.
try using $.live() instead of $.blur()
so even if this script elements are inserted after the page rendered, events will be bound to em.
http://api.jquery.com/live/

JQuery dropping click events

I'm currently experiencing click events intermittently not firing. Anyone else ever had this problem?
Code is simple:
<ul class="iconButtons ui-widget ui-helper-clearfix">
<li class="ui-state-default ui-corner-all" title="Save">
<span class="btnSave ui-icon ui-icon-disk"></span>
</li>
</ul>
$(document).ready(function() {
$(".btnSave").click(function() {
alert("Sometimes I never get called!");
});
});
Occurs frequently in all browsers. Using live demonstrates the same behaviour.
I would venture to say that there is some other complication going on to prevent what you are doing.
Here are some possibilities:
Unless you give that empty span display:block; then on some browsers it will have a width and height of 0px and be unclickable. Keep in mind just adding width and height to a span won't actually work on inline elements.
You are ajax'ing content in, and not rebinding the click handler. You can check at any time by doing $(".btnSave").data("events") in your firebug or chrome console to see the number of events to that element.
Another event is usurping your event, using the technique in #2 may help reveal this.
Your click handle is being called, but not returning the right result causing to believe it wasn't being called. Have you tried adding an alert('called') to the very top of the click handler?
Are you certain the element exists in the DOM prior to appending the click element to it? You can check by doing an alert($(".btnSave").length) at the line JUST before you bind the click handler.
I would suggest you use an anchor instead of a span for your button it will fire for sure.
Put
$(".btnSave").click(function(event){
event.preventDefault();
alert("Clicked");
});
In IE, you also have to have content inside an anchor for it to work: background image / background color/ text (maybe also with big negative text-indent)
Your code will hook up event handlers to all elements with that class that already exist when the code is called. If you add more later, they won't get the handler because, well, you haven't asked that they do. :-) Options:
You could use live instead, if you add and remove these elements dynamically. live (and the related delegate) use event delegation to watch for events rather than actually attaching the handlers to the elements in question. live uses the document itself. Since click bubbles, document sees all clicks (that aren't cancelled), and so jQuery's document-wide handler can see if the click was on a .btnSave element and fire your handler if so.
You could put your script at the bottom of the page (just before the closing </body> element), so that all of the elements are there when you hook up your handler.
You could use jQuery's ready function to ensure the DOM is ready before you hook up your handlers.
Alternately, as quoted your span is pretty darned hard to click on (what with being completely empty) unless there's some CSS giving it dimensions you haven't shown... ;-)
Update: You've said the span has dimensions, and that the handler is being hooked up fine (you didn't say how you know that). The only thing left is if something is hooking the click event on those elements and cancelling them (e.g., via stopImmediatePropagation, like this), and it happens that they're earlier in the event handler list than your handler is. It seems more likely that there's an issue hooking things up, though.
There may be many different reasons for that, eg.:
the JS code you are referring to is not executed correctly (does not bind the event in the correct moment in time), try executing it when the DOM is ready:
jQuery(function(){
// your code goes here
});
you may be creating this element dynamically (if you bind it first, then create element, then this element will not have the specific event). The solution is to use .delegate() or .live() jQuery functions.
the event may be unbound somewhere in your code. Try searching for usage of .unbind() jQuery's function within JS code (or even HTML).
It turns out the span which the click event was being added to only occupied the central part of the button's graphic. Clicking directly on the glyph always fired the event, but clicking slightly outside (although seemingly still inside the button) would not raise the event.
I hope this helps anyone else using mini JQuery buttons in the same way they are presented on the JQuery UI ThemeRoller page.
I'm running jquery-ui-1.10.3 and I'm having the same intermittent issue with .toggle buttons -- they just aren't very responsive. I think it's inherent in jquery-ui because even on their demo page the toggle button feels less-than-awesome in terms of tactile response. If I click very slowly and deliberately I can usually get the button to toggle on and off but fast clicking is very hit or miss. I've tried all the tips to speed up jquery-ui but none have worked.

Categories