Understanding event bubbling in Javascript - javascript

I've been trying to understand even bubbling, and not quite sure I completely follow it. I started reading about it so that I could warn users when they were leaving a page on my website if they had started to enter data into a form (in a similar way to Stack Overflow does!).
The following code seems to work cross-browser:
var entereddata = false;
$(document).ready(function()
{
$('#contactform').bind('keypress',function(e) {
if((e.which > 96 && e.which < 123) || (e.which > 47 && e.which < 58)) {
entereddata = true;
//alert(e.which);
}
});
});
function confirmLeave(e, d)
{
if(!e) e = window.event;//window.event;
if(!d) d = entereddata;
var confirmationMessage = 'It appears you have started to enter information into the contact form, but have not yet submitted it';
if(!d)
{
e.cancelBubble = true;
} else
{
return confirmationMessage;
}
}
window.onbeforeunload=confirmLeave;
However, this also gets called when I click the submit button for the form, which I don't want. I've tried various additions to the code, such as adding:
if($('#submit').click()){
submitted=true;
} else {
submitted=false;
}
and then changing if(!d) to if(!d && submitted==false) to the main code; however, this (and every other combination of trying to get the page to fire only if the submit button isn't clicked) doesn't work, with the warning either still showing when I click the submit button, or no warning being shown when anything is clicked!
This might boil down to the fact I don't understand the event bubbling process - I don't know why I need the e.cancelBubble = true; in the place I have it.
So, my two main problems are:
how do I check if the submit button is clicked, and only show the warning if it isn't clicked
and to understand eventBubbling; for example: if enteredData is true, then I'm not affecting the bubbling process. Should I be? Should I have e.cancelBubble=false if enteredData is false and e.cancelBubble=true if enteredData is true? What effect does setting the value of e.cancelBubble actually have when closing a page?
Am I also correct in thinking I don't need the event e.stopPropagation
at all, because Firefox supports event bubbling?

What about having such code?
$('#submit').click(function() {
entereddata = false;
});
This should be called before the actual form submission i.e. before confirmLeave is running, so lowering the flag should do the trick.

Try removing the onbeforeunload "listener":
$('#submit').click(function() {
window.onbeforeunload=null;
});
I don't think you need to worry about bubbling in this example...
return null if you want the browser to move on without asking the user, or return a string if you want the browser to show an alert asking the user if he wants to move on or not...
function confirmLeave(e) {
e = e || window.event;//window.event;
var confirmationMessage = 'It appears you have started to enter information into the contact form, but have not yet submitted it';
if(entereddata) {
return confirmationMessage;
} else {
return null;
}
}
Bubbling and propagation only applies to event's that should notify it's children or it's parents, and as far as i know window.onbeforeunload is a global event that will not be propagated.

Unrelated to bubbling, but you could bypass detecting whether keys were pressed and check the form data instead:
function hasNonemptyTextInputs() {
var textInputs = $('#contactform :input').filter(':text, textarea');
// Check for any field with a nonempty value
// .is() returns true iff the function returns true on any element
return textInputs.is(function() {
return $(this).val().length > 0;
});
}

Related

After preventing the default behavior the enter key seems to be refreshing the global variables in java script

I am writing a search function much like the [cmd+f] function in a browser. I have everything working but I want the enter key on press to cycle through the results through the page. I also have arrow buttons that call the function I wrote and they work. I prevented the default behavior of enter using:
$('form').keydown(function (event) {
if (event.keyCode == 13) {
event.preventDefault();
return false;
}
});
I am using this code to call the function on enter:
$('form').keyup(function (event) {
if (event.keyCode == 13) {
nextSearch();
}
});
It works for the first result but I think it resets the global variable I use to mark the place. The only logical answer I can think of is that pressing enter now refreshes the JavaScript. Is there a way to prevent this?
I use these global variables to keep track:
window.luCurrentNumber = 0;
window.luLastActive = 0;
If I understand you corrected, you the arrow keys and the enter keys to tab instead of performing their default. Here is an example of a function that I use to treat the Enter key as a tab, which I wrote because users kept hitting the enter key and accidentally submitting the page.
//Make enter key is pressed, tab instead of submitting.
$('body').on('keydown', 'input, select', function (e) {
var self = $(this)
, form = self.parents('form:eq(0)')
, focusable
, next
;
if (e.keyCode == 13) {
focusable = form.find('input,a,select,button').filter(':visible');
next = focusable.eq(focusable.index(this) + 1);
if (next.length) {
next.focus();
} else {
form.submit();
}
return false;
}
});
Though it's not exactly what you are trying to do, I think it should set you on the right path.

redirect to other page if click on leave page

How can i redirect him if a user clicks on leave a page button on onbeforeunload. Please check my code
function openNewWindow() {
window.open('http://google.com/','_blank');
window.focus();
}
window.onbeforeunload = function(event) {
event = event || window.event;
var confirmClose = 'Are you sure?';
if (event) {
event.returnValue = confirmClose;
if(confirmClose)
{
if(true)
{
openNewWindow();
}
}
return confirmClose;
}
}
Thanks
If the users chooses yes in the onbeforeunload dialog then he will leave the page, you can not prevent this. You can however do some things before the dialog shows, like you are doing in your code, but the dialog it self is only displayed AFTER your function executes, displaying the return value.
Your code seems a bit obscure to, what are you expecting from if(confirmClose), this will always evaluate to true because a non empty string is "truthy" in javascript.

Problem with event.target in IE

I'm writing js for a status update system to be used on various pages throughout a app that I'm working. I am really just starting to get more comfortable with javascript so it has been somewhat of a challenge to get to the point where I have everything now.
The status system is basically a facebook clone. For the most part everything is supposed to function the way that facebook's status updates and status comments do. The intended behavior is that when the user clicks in the status textarea, the div under the status textarea slides out revealing the submit button as well as some other checkboxes.
If the user clicks anywhere else on the page except a link or any element that has the class prevent_slideup the div slides up hiding the submit button and any checkboxes.
I'm using a document.body click function to determine what the user clicked on so I know which form elements to hide if I should even hide them. I do not want this slideup to take place on a textarea if that textarea has focus or the user is selecting a checkbox that goes with that form. Hence the prevent_slideup class. I also do not want to bother running the slideup logic if the user has clicked on a link. I'd prefer they just leave the page without having to wait for the animation.
The code that I was using to accomplish this task can be found in the $(document.body).click(function (e) section below where I'm doing a .is('a') check on the event target.
This code works as expected in chrome and firefox, however in ie when a link is clicked for the first time it seems that the element stored in var target is actually a div instead of an anchor. What ends up happening is that the submit div slides up and the user is not taken to the link that they just clicked on. If a link is clicked a second time the user is taken to the page as you would expect.
It seems to me that there's some kind of a lag in ie as to what the current event being fired is.
The entire status module is working other than this one strange ie bug regarding the users click on the link not being carried out the first time that they click a link after opening the status textarea. Does anything jump out in this script that would explain this behavior or does anyone have any other advice?
Thanks in advance for your help.
$(document).ready(function(){
$("textarea.autoresize").autoResize();
});
$(document.body).click(function (e){
var target = e.target || e.srcElement;
console.log(target);
console.log($(target).is('a'));
if($(target).hasClass('prevent_slideup') || $(target).is('a'))
{
return true;
}
else
{
var active_element = document.activeElement;
var active_status_id = $(active_element).attr('data-status_id');
var active_has_data_status_id = (typeof active_status_id !== 'undefined' && active_status_id !== false) ? true : false;
$('textarea').each(function(){
if($(this).hasClass('status_comment_textarea'))
{
var status_id = $(this).attr('data-status_id');
if($('#comment_textarea_'+status_id).val() === '' && (!active_has_data_status_id || active_status_id !== status_id))
{
hide_status_comment_submit(status_id);
}
}
else if($(this).attr('id') === 'status_textarea')
{
if($('#status_textarea').val() === '' && $(active_element).attr('id') !== 'status_textarea')
{
$('#status_textarea').html($("#status_textarea").attr('placeholder'));
hide_status_submit();
}
}
});
return true;
}
});
$("#status_textarea").live('click', function(){
if($('#status_textarea').val() === $("#status_textarea").attr('placeholder'))
{
$('#status_textarea').html('');
}
show_status_submit();
return false;
});
$(".comment_toggle").live('click', function(){
var status_id = $(this).attr('data-status_id');
show_status_comment_submit(status_id);
return false;
});
$(".status_comment_submit").live('click', function(){
var status_id = $(this).attr('data-status_id');
$('#status_comment_submit_wrapper_'+status_id).addClass('status_comment_submit_successful');
return false;
});
$(".show_hidden_comments").live('click', function(){
var status_id = $(this).attr('data-status_id');
$('#status_hidden_comments_'+status_id).show();
$(this).hide();
return false;
});
function hide_status_submit()
{
$("#status_textarea").removeAttr('style');
$("#status_textarea").blur();
$("#status_block").removeClass('padding_b10');
$("#status_submit_wrapper").slideUp("fast");
return false;
}
function show_status_submit()
{
if ($("#status_submit_wrapper").is(":hidden"))
{
$("#status_block").addClass('padding_b10');
$("#status_submit_wrapper").slideDown('fast');
}
return false;
}
function hide_status_comment_submit(status_id)
{
if(!$('#status_comment_submit_wrapper_'+status_id).is(":hidden"))
{
$('#status_comment_submit_wrapper_'+status_id).hide();
$('#fake_comment_input_'+status_id).show();
$('#comment_textarea_'+status_id).removeAttr('style');
}
return false;
}
function show_status_comment_submit(status_id)
{
if($('#status_comment_submit_wrapper_'+status_id).is(":hidden"))
{
$('#fake_comment_input_'+status_id).hide();
$('#status_comment_submit_wrapper_'+status_id).show();
$('#comment_textarea_'+status_id).focus();
}
return false;
}
function status_comment_submit_successful()
{
hide_status_comment_submit($('.status_comment_submit_successful').attr('data-status_id'));
$('.status_comment_submit_successful').removeClass('status_comment_submit_successful');
return false;
}
I figured out that there were two main issues with my script...
1.) The document.body function and the #status_textarea live click funtioins were conflicting with each other.
2.) After adding the logic for the #status_textarea function into the document.body function I noticed that the script still didn't quite work as expected in internet explorer unless I had an alert in the function. The problem at this point was that the autoresize plugin that I'm using on the textarea was also conflicting with the document.body function.
I was able to rectify the situation by adding a dummy text input and hiding the status textarea. On click of the dummy text input the status textarea is shown and the the dummy text input is hidden. I have no idea why this worked, but it seems to have solved my problems.

Disabling enter key for form

I have been trying to disable the Enter key on my form. The code that I have is shown below. For some reason the enter key is still triggering the submit. The code is in my head section and seems to be correct from other sources.
disableEnterKey: function disableEnterKey(e){
var key;
if(window.event)
key = window.event.keyCode; //IE
else
key = e.which; //firefox
return (key != 13);
},
if you use jQuery, its quite simple. Here you go
$(document).keypress(
function(event){
if (event.which == '13') {
event.preventDefault();
}
});
Most of the answers are in jquery. You can do this perfectly in pure Javascript, simple and no library required. Here it is:
<script type="text/javascript">
window.addEventListener('keydown',function(e){if(e.keyIdentifier=='U+000A'||e.keyIdentifier=='Enter'||e.keyCode==13){if(e.target.nodeName=='INPUT'&&e.target.type=='text'){e.preventDefault();return false;}}},true);
</script>
This code works great because, it only disables the "Enter" keypress action for input type='text'. This means visitors are still able to use "Enter" key in textarea and across all of the web page. They will still be able to submit the form by going to the "Submit" button with "Tab" keys and hitting "Enter".
Here are some highlights:
It is in pure javascript (no library required).
Not only it checks the key pressed, it confirms if the "Enter" is hit on the input type='text' form element. (Which causes the most faulty form submits
Together with the above, user can use "Enter" key anywhere else.
It is short, clean, fast and straight to the point.
If you want to disable "Enter" for other actions as well, you can add console.log(e); for your your test purposes, and hit F12 in chrome, go to "console" tab and hit "backspace" on the page and look inside it to see what values are returned, then you can target all of those parameters to further enhance the code above to suit your needs for "e.target.nodeName", "e.target.type" and many more...
In your form tag just paste this:
onkeypress="return event.keyCode != 13;"
Example
<input type="text" class="search" placeholder="search" onkeypress="return event.keyCode != 13;">
This can be useful if you want to do search when typing and ignoring ENTER.
/// Grab the search term
const searchInput = document.querySelector('.search')
/// Update search term when typing
searchInput.addEventListener('keyup', displayMatches)
try this ^^
$(document).ready(function() {
$("form").bind("keypress", function(e) {
if (e.keyCode == 13) {
return false;
}
});
});
Hope this helps
For a non-javascript solution, try putting a <button disabled>Submit</button> into your form, positioned before any other submit buttons/inputs. I suggest immediately after the <form> opening tag (and using CSS to hide it, accesskey='-1' to get it out of the tab sequence, etc)
AFAICT, user agents look for the first submit button when ENTER is hit in an input, and if that button is disabled will then stop looking for another.
A form element's default button is the first submit button in tree order whose form owner is that form element.
If the user agent supports letting the user submit a form implicitly (for example, on some platforms hitting the "enter" key while a text field is focused implicitly submits the form), then doing so for a form whose default button has a defined activation behavior must cause the user agent to run synthetic click activation steps on that default button.
Consequently, if the default button is disabled, the form is not submitted when such an implicit submission mechanism is used. (A button has no activation behavior when disabled.)
https://www.w3.org/TR/html5/forms.html#implicit-submission
However, I do know that Safari 10 MacOS misbehaves here, submitting the form even if the default button is disabled.
So, if you can assume javascript, insert <button onclick="return false;">Submit</button> instead. On ENTER, the onclick handler will get called, and since it returns false the submission process stops. Browsers I've tested this with won't even do the browser-validation thing (focussing the first invalid form control, displaying an error message, etc).
The solution is so simple:
Replace type "Submit" with button
<input type="button" value="Submit" onclick="this.form.submit()" />
this is in pure javascript
document.addEventListener('keypress', function (e) {
if (e.keyCode === 13 || e.which === 13) {
e.preventDefault();
return false;
}
});
Here's a simple way to accomplish this with jQuery that limits it to the appropriate input elements:
//prevent submission of forms when pressing Enter key in a text input
$(document).on('keypress', ':input:not(textarea):not([type=submit])', function (e) {
if (e.which == 13) e.preventDefault();
});
Thanks to this answer: https://stackoverflow.com/a/1977126/560114.
Just add following code in <Head> Tag in your HTML Code. It will Form submission on Enter Key For all fields on form.
<script type="text/javascript">
function stopEnterKey(evt) {
var evt = (evt) ? evt : ((event) ? event : null);
var node = (evt.target) ? evt.target : ((evt.srcElement) ? evt.srcElement : null);
if ((evt.keyCode == 13) && (node.type == "text")) { return false; }
}
document.onkeypress = stopEnterKey;
</script>
You can try something like this, if you use jQuery.
$("form").bind("keydown", function(e) {
if (e.keyCode === 13) return false;
});
That will wait for a keydown, if it is Enter, it will do nothing.
I checked all the above solutions, they don't work. The only possible solution is to catch 'onkeydown' event for each input of the form.
You need to attach disableAllInputs to onload of the page or via jquery ready()
/*
* Prevents default behavior of pushing enter button. This method doesn't work,
* if bind it to the 'onkeydown' of the document|form, or to the 'onkeypress' of
* the input. So method should be attached directly to the input 'onkeydown'
*/
function preventEnterKey(e) {
// W3C (Chrome|FF) || IE
e = e || window.event;
var keycode = e.which || e.keyCode;
if (keycode == 13) { // Key code of enter button
// Cancel default action
if (e.preventDefault) { // W3C
e.preventDefault();
} else { // IE
e.returnValue = false;
}
// Cancel visible action
if (e.stopPropagation) { // W3C
e.stopPropagation();
} else { // IE
e.cancelBubble = true;
}
// We don't need anything else
return false;
}
}
/* Disable enter key for all inputs of the document */
function disableAllInputs() {
try {
var els = document.getElementsByTagName('input');
if (els) {
for ( var i = 0; i < els.length; i++) {
els[i].onkeydown = preventEnterKey;
}
}
} catch (e) {
}
}
I think setting a class to a form is much better. so I coded that:
HTML
<form class="submit-disabled">
JS
/**
* <Start>
* Submit Disabled Form
*/
document
.querySelector('.submit-disabled')
.addEventListener('submit', function (e) {
e.preventDefault()
});
/**
* </End>
* Submit Disabled Form
*/
And also if you want to disable submitting only when Enter Key press:
/**
* <Start>
* Submit Disabled Form
*/
document
.querySelector('.submit-disabled')
.addEventListener('keypress', function (e) {
if (e.keyCode === 13) {
e.preventDefault()
}
});
/**
* </End>
* Submit Disabled Form
*/
in HTML file:
#keypress="disableEnterKey($event)"
in js file:
disableEnterKey(e) {
if (e.keyCode === 13) {
e.preventDefault();
}
}
First you need to disable the form on submit, but re-enable it when clicked on the button. which or keycode is not used in this case, avoiding some problems with compatibility.
let formExample = document.getElementbyId("formExample");//selects the form
formExample.addEventListener("submit", function(event){ //must be used "submit"
event.preventDefault();// prevents "form" from being sent
})
To reactivate and submit the form by clicking the button:
let exampleButton = document.getElementById("exampleButton");
exampleButton.addEventListener("click", activateButton); //calls the function "activateButton()" on click
function activateButton(){
formExample.submit(); //submits the form
}
a variation of this would be
let exampleButton = document.getElementById("exampleButton");
exampleButton.addEventListener("click", activateBtnConditions); //calls the function "activateBtnConditions()" on click
function activateBtnConditions(){
if(condition){
instruction
}
else{
formExample.submit()
}
}
Here is a modern, simple and reactive solution which works in:
React, Solidjs, JSX etc.
is written in Typescript
supports server-side rendering (SSR)
all modern browsers
does NOT require jQuery
blocks ALL Enter keys outside of <textarea> where you want to allow Enter
// avoids accidential form submission, add via event listener
function blockEnterKey(e: KeyboardEvent) {
if (e.key == "Enter" && !(e.target instanceof HTMLTextAreaElement)) {
e.preventDefault()
}
}
// add the event listener before the rendering return in React, etc.
if (typeof window !== undefined) {
window.addEventListener("keydown", blockEnterKey)
// the following line is for Solidjs. React has similar cleanup functionality
// onCleanup(() => document.body.removeEventListener("keydown", blockEnterKey))
}
return(
<form>
...
</form>
)
The better way I found here:
Dream.In.Code
action="javascript: void(0)" or action="return false;" (doesn't work on me)

ASP.NET Post-Back and window.onload

I got a function which checks if some input fields are changed:
var somethingchanged = false;
$(".container-box fieldset input").change(function() {
somethingchanged = true;
});
And a function which waits on window.onload and fires this:
window.onbeforeunload = function(e) {
if (somethingchanged) {
var message = "Fields have been edited without saving - continue?";
if (typeof e == "undefined") {
e = window.event;
}
if (e) {
e.returnValue = message;
}
return message;
}
}
But if I edit some of the fields and hit the save button, the event triggers, because there is a post-back and the fields have been edited. Is there anyway around this, so the event does not fire upon clicking the save button?
Thanks
When I do this pattern I have a showDirtyPrompt on the page. Then whenever an action occurs which I don't want to go through the dirty check I just set the variable to false. You can do this on the client side click event of the button.
The nice thing about this is that there might be other cases where you don't want to prompt, the user you might have other buttons which do other post backs for example. This way your dirty check function doesn't have to check several buttons, you flip the responsability around.
<input type="button" onclick="javascript:showDirtyPrompt=false;".../>
function unloadHandler()
{
if (showDirtyPrompt)
{
//have your regular logic run here
}
showDirtyPrompt=true;
}
Yes. Check to see that the button clicked is not the save button. So it could be something like
if ($this.id.not("savebuttonID")) {
trigger stuff
}

Categories