I ran into an incredibly obscure-seeming bug and want to document it for posterity. Here’s what happened:
I’m displaying an HTML form to the user with many text fields and a submit button at bottom. Just above the submit button is a warning message that appears or disappears depending on whether the user has filled in all the required information. During testing (automated using Capybara, or manual in the browser) I fill in each field down the page, then click on the Submit button, but the first click doesn’t register. A second click submits the form as expected.
I found that if I disable my custom Javascript, no second click is required. After some process-of-elimination I determined that one Jquery line was responsible for the failure: $(‘#warning-message’).hide();. Comment out this line, and filling out and submitting the form works as expected. Re-enable this line, and form submission requires that extra click. What the frak?
I eventually figured out this was because, both during manual testing and when simulated by Capybara-webkit, when you click on an element like a submit button, that’s registered as a specific X/Y coordinate on the screen. You're not clicking on the DOM element, you're clicking on a coordinate. Because of the (lazy) way I set up this page, when I fill out all the required elements then click Submit, upon clicking the submit button a Jquery change event is triggered which causes $(‘#warning-message’).hide();, which in turn causes the submit button to jump up outside of the area that I had clicked on, so the submit event never gets triggered in the first place because the browser doesn't realize that I clicked on a button.
I’m still not clear what to make of this, but it’s definitely not a bug per se, so much as a misunderstanding (on my part) of how browser events are handled. I’ve worked around the issue by wrapping the warning div in a fixed-height container so unrelated Jquery change events can't cause the submit button to jump around.
Anyway I hope this helps someone.
Related
I have a form that I create within a Bootbox (itself a layer on top of Bootstrap's modal). Once it is created, I call
$('#myForm').validate()
on it.
The desirable part of the behaviour is that now as the user tabs through the forms, they can see immediate feedback that they've messed up one of the fields. Entered a non-email address before hitting "tab" or clicking elsewhere? Warning and error message. Great!
But the undesirable thing is that the blur eats other events. So, if a user instead chooses to hit "cancel" (knowing full well that the form is invalid), the click on the cancel is not heard and its handler will not fire. A second click (now that the focus is off the form altogether) and cancel fires as expected. I don't want the users to have to click twice.
I saw a technique for disabling the blur altogether, but then the desirable behaviour described above is then lost, which I do not want either. Ideally, a "well, I blurred, but I also know what the user was clicking" is what I'm after.
[EDIT TO ADD:]
It has come to my attention that this is confusing, so let me try a different approach to the question: is it possible to be working on a form (that has had .validate() called on it), then click on any other clickable item on the whole page and have its click handler successfully fire?
[EDIT AGAIN:]
Based on Sparky's demo, I wired up a warning to show below the inputs on blur. So, to see the problem in action, fire up this fiddle: https://jsfiddle.net/bd1fhpu3/
Then click into one of the input fields BEFORE clicking "just a button". Click in an upper sliver of "just a button" to make sure that the warning labels have pushed it out of the cursor's hotspot on release of the mouse button.
Anyhow, this just explains what the problem is. Solving it is probably not within the scope of the question anymore, but it seemed worth sharing in case anybody else comes across this. To solve, I will either need to override Bootbox's click event to be a mousedown event instead of a click (then you don't need to press and release), or I can "Band-Aid"(tm) the solution by avoiding relocating the button. Maybe a static-height dialog that's tall enough to accomodate the form and any possible warnings. Definitely somewhat of a "hack" like this because you just never know if you're going to do other things later that make the problem appear again. But it'd be a quick and easy temp fix.
You cannot use the built in onfocuout function since the JavaScript cannot possibly know the different between focusing out to another field and focusing out to the cancel button.
You'll have to completely disable onfocusout and write some custom event handlers.
Your code is sparse, so my answer will be very generic.
$('#myForm').validate({
// other options here
onfocusout: false; // disable default blur event
});
Then write an event handler that programmatically triggers validation on the form when they focus to an input, and will do nothing when they focus over to anything, like a cancel button.
$('#myForm input').on('focus', function() {
$('#myForm').valid(); // trigger validation on the form
});
However, this will trigger validation on the entire form. If you only want to trigger validation on the one field losing focus, then you're back to square one, because the event only knows focus was lost, not where it's going.
Just for posterity, here's an "answer" such as it is. Maybe it will help somebody SOME day; you just never know.
There is no code that is operating "incorrectly" and therefore there is not really a fix nor code sample to provide. Here's what was happening:
User is in focus in field
User presses mouse button down (but the release action hasn't happened yet)
Blur event fires, which causes form error warnings to appear below the fields. This also had the net effect of pushing the "cancel" button down the Y axis of the screen
User releases the mouse button, which would normally complete the "click" handler.
HOWEVER, in #4, since the "cancel" button is no longer under the cursor, the click event listener bound to the button does not fire.
The demo, for as long as it lives on the internet, will be in a comment below. However, providing a code sample to go with it is pointless. When the demo dies, I will remove the comment.
Possible Steps (workarounds/hacks) that I elected NOT to pursue thus far:
Modify the dialog such that the button does not move when mousedown event fires, meaning the "click" event is completed successfully
Provide custom code that substitutes the mousedown event for the click event on the button. However, this causes a loss of fairly common UI convention
Force user to press ESC to cancel, rather than clicking a button
[credit to Tieson T. via comment] One possible option, if you can use some custom styles on the error messages, is to hide them with visibility: none rather than display: none. The former would hide the text but still reserve the vertical space of the text, which the latter doesn't (hence why your modal is expanding). This would keep the button from possibly shifting during the focusout event. You would wind up with extra whitespace, but you could knock some of that off by removing the bottom margin on the form-group (assuming you're using it)
I'm sure there are other workarounds, but that's a starting point.
I'm using Nightwatch.js to perform e2e testing on my Vue.js application. My application contains long forms, which "hides" the buttons outside of the view while performing the tests.
I looked into many questions that suggests the usage of getLocationInView, but the documentation clearly says
Determine an element's location on the screen once it has been scrolled into view
I tried using something like
browser
.url("http://localhost:8080")
.setValue("#email", "valid4#mail.ca")
.getLocationInView("#myElement")
.submit() //defined elsewhere
.waitForElementVisible("#error", 3000);
This snippet is supposed to click on a button at the bottom of the form, that's what submit() does but when I get the error screenshot to find that no scrolling down whatsoever has happened, leading the button to stay out of focus and therefore unclicked!
is there a way to ultimately scroll to the bottom of the page so I can pass the tests without having to change or at least with minimum changes to my original code?
Rather than using submit, use elementIdClick .
The documentation says that this method would scroll the element into view. This would click the button to submit the form rather than attempting to submit the form without interacting with the button.
This seems like a more 'authentic' way to test since users would click the button at the button of the form anyways. Otherwise as you know, the test will keep failing since the button is not in view.
EDIT:
Check out this answer as well: nightwatch.js - scroll until element is visible
Clicking a button requires scrolling to that button to bring it on the screen first, but apparently setValue will do the scrolling itself. so instead of scrolling then clicking, I set the value of the button in this way:
browser
.url("http://localhost:8080")
.setValue("#email", "valid4#mail.ca")
.setValue("#submitButton", " ") //<---this line
.waitForElementVisible("#error", 3000)
this is like setting focus to the element (the button) then hitting the space bar.
This is not of course the best way to do it, but I think it might be a helpful workaround if your form does not have space and enter restricted from submitting/triggering the button.
I have a small query, I have a multiple dropdown box in my form. after selecting multiple value, if I click on outside the multiple drop down box page should reload. How can I make it happen using javascript. I have used "onmouseout(reload.form)" option but it is not working. Please help me on this.
Thanks
Ranjith
In this scenario, you might need click event rather mouseout(which is not on click but when mouse loses the focus).
For more details about click outside the element refer the below link
Javascript Detect Click event outside of div
So once you capture the click out event, you can just trigger the page load using
window.location.reload(true) or window.location.reload(false)
true or false depends on you need to load from cache or server.
Hope it helps!!
Seems like you should really connect to the change() signal on the select box instead. By depending on the mouse event, you will prevent people form using your form with the keyboard only, for instance. onmouseout will also not work on mobile devices
I'm using jquery's bPopup() to open a modal window. When the user clicks a button, jquery loads an ajax page and then shows the modal windows. Due to this small delay when loading the page, the button remains active, and if the user clicks twice, it will fire twice, making two ajax requests to the server and opening two windows.
Is there a simple way to prevent this from happening? Since it's relatively a common problem, I wonder if there's a "right" way the pros handle it.
I've tried assigining the popup to a window.object, so that it would be overwritten on the second call, but it's still opening two popups.
That depends on what UX you're after, but I'd suggest you disable the button.
That way your user will:
Know the click was "registered".
Not try to click again.
Not crash / confuse you code.
EDIT
According to the comment, the "button" is actually not a <button>, but an element with an onclick handler. So:
You can disable the click handler by reversing what you did to set it (removeEventHandler, onclick=null...), but you'd then have to set it back once the pop-up is done, and that might be quite annoying.
You'd have to somehow manipulate the UI to indicate the button was clicked and is disabled. Could probably be quite simple to do with a CSS class.
But really, you're probably better off having 2 "versions" of your button element (<div>...), with only 1 visible at a time, with the other hidden via display: none. The "clicked" version should not have a click event handler set at all. Then, when the button is clicked, you immediately switch between the 2 (can be done with a single CSS class), and once the pop-up is done, switch back.
I am trying to fill a website with the help of a greasemonkey script.
This website has some required fields and I can't submit the form when they are not filled in.
Now, I have the following problem:
I fill the required fields using jQuery's .val. When I now click the submit button - even manually with the mouse - then it says that some of the required fields are not filled in.
When I click in one of the affected fields with the mouse and then click the submit button again, it accepts the value and proceeds.
My question is:
How do I figure out which event the website listens to? Or:
How can I trigger the validation of the fields from my script?
Update: I tried the following command directly in Chrome's developer tools' console:
jQuery('#ext-comp-1080').click().focus().focusin()
.val('my value').change().blur().focusout()
Most often, the validation is tied to a blur event.
In jQuery, you would use:
$('#thingToBlur').blur();
That said -- I have never triggered events through a UserScript, so I'm not sure if they will correctly hit the element in unsafeWindow.
If you need to force-ably run JavaScript on the page (and that includes firing the events there), see this question:
UserScripts & Greasemonkey: calling a website's JavaScript functions
Since after you change the file by using .val() and then you click into a field and click submit it most likely listens on change or blur event.
// set value
$(selector).val(value);
// trigger click
$(selector).click();
// trigger change or blur
$(selector).change();
You could also do method chaining if you wanted.