I have a form that is split into sections. When the user clicks "continue", I have a jquery script that checks to see if all required fields are filled out. If any aren't, then a box appears with a warning and buttons (They are actually <a> tags) for 'yes' and 'no'. I attach an onclick event to the 'yes' button that triggers a function. The function works, but a # appears in the address bar (website.com/page#), which I'm guessing is because the event.preventDefault(); in my code isn't working.
Here is the function that adds the onclick event:
function checkSection (event, check, goTo) {
event.preventDefault();
var emptyFields = "0";
$("#ia"+check+"Div .check").each(function() {
var val = $(this).val();
if (val == "") {
emptyFields++;
}
});
if (emptyFields >= 1) {
$(".mask").show();
$("#warningBox").show();
$(document).on("click", "#yesBtn", function() {
var x = window['save'+check];
x(event, goTo);
$("#warningBox").hide();
$(".mask").hide();
});
} else {
var x = window['save'+check];
x(event, goTo);
$("#warningBox").hide();
}
}
Here is the tag I am adding the event to:
<div class="medBtn short">
<div class="btnTbl">
Yes
</div>
</div>
The function I end up calling is like this:
function saveContact(event, val) {
event.preventDefault();
//Do Stuff - This is the function where event.preventDefault(); isn't working
}
Like I said, the function still works, so if it's not something I can get around, that is fine. I just don't like having a # in the address bar.
The event object doesn't exist until the event occurs
You prevent default inside the actual event handler
$(document).on("click", "#yesBtn", function(event) {
event.preventDefault();
....
})
Related
I have a div which contains an input element to enter some values. These values are added just above the div as a list element upon pressing enter or onFocusOut event. To this point it is fine. But if user types some value and does not press enter and directly clicks on save button, the onFocusOut function for that div should not be called. Instead it should take that typed value and call some save function. Do you have any suggestion on how to detect it?
My code snippet is here
JS:
divInput.onkeypress = function (event){
return someTestFunc();
}
divInput.tabIndex="-1";
$(divInput).focusout(function (e) {
if ($(this).find(e.relatedTarget).length == 0) {
addToList();
}
});
It is not a very delicate solution, but you could use a setTimeout before adding the item to the list and clear the setTimeout on save.button click.
Try this:
var $saveButton = $('#exampleButton')[0],
$divInput = $('#exampleInput')[0],
timedEvent = -1;
$($saveButton).on('click', function(event){
if(timedEvent) {
clearTimeout(timedEvent)
}
alert('not add to list & save');
})
$divInput.tabIndex="-1";
$($divInput).on('focusout', function(e) {
timedEvent = window.setTimeout(function() {
if ($(this).find(e.relatedTarget).length == 0) {
alert('add to list');
}
}, 200);
});
Check this working fiddle
(Fiddle: http://jsfiddle.net/qdP3j/)
I have this div:
<div id="addContactList"></div>
I use AJAX and change its innerHTML with something like:
<div id="<%= data[i].id %>">
<img src="<%= picture %>">
<button class="addAsFriend">Add as Friend</button>
</div>
In my JS, I have
$('#addContactList').on('click', '.addAsFriend', function () {
$(this).text('Request sent!');
$(this).attr('disabled','disabled');
});
What happens is that when I click on a button for the first time, I see that the click function ran; "Request sent!" is being shown but it immediately reverts back to the initial button. When I click a second time, it works fine.
I tried using event.stopPropagation and preventDefault but same issue happens.
As stated, it probably comes from the AJAX part:
Basically, I have 3 input fields on a page, and users can enter data in them. If there is data in the fields, they are posted and I use the data to query the database. There is a delay function of 250ms to prevent posting immediately every time a letter is typed.
var addContactsList = document.getElementById('addContactList');
$('#addContactForm').on('keyup change', function () {
var self = this;
// Add a short delay to not post for every letter typed quickly
delay(function() {
var userSearchData = {};
userSearchData.userId = 23;
$.each(['email', 'username', 'fullName'], function (_, el) {
var val = $(self).find('input[name="' + el + '"]').val();
if (val.length >= 3) {
userSearchData[el] = val;
}
});
if ( !isEmpty(userSearchData) ) {
$.post('/post/addContact', { userSearchData: userSearchData }, function (data) {
if (data) {
new EJS({url: '/templates/addAContact.ejs'}).update('addContactList', { data: data })
} else {
addContactsList.innerHTML = '';
}
});
} else {
addContactsList.innerHTML = '';
}
}, 225 );
});
It's because of the "keyup change". Change was being triggered again when clicking elsewhere (the add friend button).
Now though the problem is when people use the autocomplete feature using the mouse, it will not trigger because change isn't there anymore.
As you noticed, the change event fires when your input field loses focus (when you click on the button). You can keep the change event, and check if the change event is firing while the input field is focussed
$('#addContactForm').on('keyup change', function () {
if (!$(document.activeElement).is('input')) return; //add this line
How to add multiple event listeners in the same initialization?
For example:
<input type="text" id="text">
<button id="button_click">Search</button>
JavaScript:
var myElement = document.getElementById('button_click');
myElement.addEventListener('click', myFunc());
This is working correctly however I would like to have another event listener for this input filed in the same call if that is possible, so when user clicks enter or presses the button it triggers the same event listener.
Just one note. User needs to be focused on the input field to trigger an "enter" event.
Just bind your function to 2 listeners, each one of the wished element:
document.getElementById('button_click').addEventListener('click', myFunc);
document.getElementById('text').addEventListener('keyup', keyupFunc);
where the new function test if the user pressed enter and then execute the other function :
function keyupFunc(evt) {
if(evt.keyCode === 13) // keycode for return
myFunc();
}
Working jsFiddle : http://jsfiddle.net/cG7HW/
Try this:
function addMultipleEvents(elements, events){
var tokens = events.split(" ");
if(tokens.length == elements.length){
for(var i = 0; i< tokens.length; i++){
elements[i].addEventListener(tokens[i], (e.which == 13 || e.which == 48)?myFunc:); //not myFunc()
}
}
}
var textObj = document.getElementById("textId");
var btnObj = document.getElementById("btnId");
addMultipleEvents([textObj,btnObj], 'click keyup');
UPDATE:
function addMultipleEvents(elements, events) {
var tokens = events.split(" ");
if (tokens.length == elements.length) {
for (var i = 0; i < tokens.length; i++) {
elements[i].addEventListener(tokens[i], myFunc); //not myFunc()
}
}
}
var textObj = document.getElementById("textId");
var btnObj = document.getElementById("btnId");
addMultipleEvents([btnObj, textObj], 'click keyup');
function myFunc(e) {
if (e.which == 13 || e.which == 1) {
alert("hello");
}
}
Working Fiddle
I think the best way to do this is by using for loops.
const events = ["click", "mouseover"]
for (i in events) {
document.getElementById("button_click").addEventListener(events[i], () => myFunc())
}
The code above loops through every events inside an array and adds it to the button.
Yeah this is a good question and can apply to other scenarios. You have a form and a user will have input text field, a radio box, a select option. So now you want the submit button to go from disabled to enabled. You decide to add an event listener to check if fieldA and fieldB and fieldC is first to enable submit button.
If you use event listener on Keyup", and all your fields are valid, the submit button will become enabled only if the last field is a text field because the event will only be triggered when you let go the key. This means it will not trigger if the radio box or select option is selected with your mouse. We must not rely in the order the fields are filled for the logic to work. Again, If you use "click", it sucks, because user will have to click somewhere on page in order for the event listener to fire and run the logic. So i think we'll need an event lister on mouseup, keyup and change for this example below. I assume you made all your validations and variables for the form fields already. We need a function with parameters of multiple events names as a string, the element we want to target (document, or button or form), and a custom function that contains our logic.
// Create function that takes parameters of multiple event listeners, an element to target, and a function to execute logic
function enableTheSubmitButton(element, eventNamesString, customFunction) {
eventNamesString.split(' ').forEach(e => element.addEventListener(e, listener, false));
}
// Call the above function and loop through the three event names inside the string, then invoke each event name to your customFunction, you can add more events or change the event names maybe mousedown, keyup etc.
enableSubmitButton(document, 'keyup mouseup change', function(){
// The logic inside your customFunction
if (isNameValid && isLocationValid && isProjectValid){
publishButton.disabled = false;
} else {
publishButton.disabled = true;
// Do more stuff like: "Hey your fields are not valid."
}
});
// The isNameValid isLocationValid, isProjectValid are coming from your previous validation Javascript for perhaps a select field, radio buttons, and text fields. I am adding it as an example, they have to be equal to true.
// The publishButton is a variable to target the form submit button of which you want enabled or disabled based one weather the form fields are valid or not.
// For example: const publishButton = document.getElementById("publish");
I have a method which is called onClick of some element. In that function I have an event handler( JQuery $().click() ), that detects the click of a button and performs some action.
I have noticed that the event handler works fine as long as it is the last block of statement in the function and is skipped altogether if there lie certain code block after it. Why is that happening?
EDIT Adding code
function launchPopUp(ID) {
if ($('#popUp').is(':hidden')) {
var serial = ID.id; // ID of the element or area clicked.
var headData = 'SVG PopUp';
var entData = 'Enter the data you want to store:';
var ok = "No";
var input = "";
var header = addHeader(headData);
var enterable = addEnterable(entData);
var buttons = addButtons();
$('#popUp').append(header);
$('#popUp').append(enterable);
$('#popUp').append(buttons);
$('#popUp').show();
$('#btnSubmit').click(function() {
input = document.getElementById('txtData').value;
if (input != "") {
ok = "yes";
$(ID).css('fill', 'green'); // Change colour to green only if some valid data is entered.
closePopUp();
}
});
var collData = { "ID": serial, "header": headData, "OK": ok, "input": input };
collection.push(collData);
}
}
Control is jumping straightaway to the code block after the .click()
You are misunderstanding the event handlers.
Javascript has asynchronous nature, so (in normal cases) there is no "waiting" for an event.
You register an eventhandler like your click() and then the function is executed when (eventually) a click on that element is registered. In the meantime the execution of the rest of your code goes on.
If you want to make your code dependent on the click, you have to write this code into the function of the click handler or pass a callback to the function.
Registering Event-Handlers is a one-time process and has to be done outside your function - at the moment you are registering a new click-handler every time you call launchPopUp. E.g. if you are calling launchPopUp five times, your code
input = document.getElementById('txtData').value;
if (input != "") {
ok = "yes";
$(ID).css('fill', 'green');
closePopUp();
}
also gets executed five times as soon as you click on #btnSubmit.
Basically you have to structure your code like the following:
register eventhandler for #btnSubmit - define what is happening when the button is clicked in this function (evaluation of your inputs)
write the launchPopUp function which gets eventually executed. No eventhandler in here and no evaluation code on btnSubmit this is all done in your eventhandler.
I think this is what you want:
function launchPopUp(ID) {
if ($('#popUp').is(':hidden')) {
var serial = ID.id; // ID of the element or area clicked.
var headData = 'SVG PopUp';
var entData = 'Enter the data you want to store:';
var ok = "No";
var input = "";
var header = addHeader(headData);
var enterable = addEnterable(entData);
var buttons = addButtons();
$('#popUp').append(header);
$('#popUp').append(enterable);
$('#popUp').append(buttons);
$('#popUp').show();
var collData = { "ID": serial, "header": headData, "OK": ok, "input": input };
collection.push(collData);
$('#btnSubmit').click(function() {
input = document.getElementById('txtData').value;
if (input != "") {
collData.OK = "yes";
$(ID).css('fill', 'green'); // Change colour to green only if some valid data is entered.
closePopUp();
}
});
}
}
Note that the collData is a variable containing a reference to an object. That object is added to the collection, and modified within the click handler when the btnSubmit button is clicked. This way, if the save button is never clicked, the object is still added to the collection. But if it is clicked, the object is changed, and closePopUp() is called, presumably allowing you to do what you need to do with the objects which exist in the collection variable.
$('#btnSubmit').click(function() {
input = document.getElementById('txtData').value;
if (input != "") {
ok = "yes";
$(ID).css('fill', 'green'); // Change colour to green only if some valid data is entered.
closePopUp();
}
});
Put the above outside your loadPopup function and put it in a
$(document).ready(function()
{
});
That might just solve it.
EDIT:
$('#btnSubmit').click(function()
{
input = document.getElementById('txtData').value;
if (input != "")
{
ok = "yes";
$(ID).css('fill', 'green'); // Change colour to green only if some valid data is entered.
closePopUp();
}
var collData = { "ID": serial, "header": headData, "OK": ok, "input": input };
collection.push(collData);
});
var collData should be IN your click function, then it will be executed when you click on the submit button.
The above code will not work good if I understand it correctly. It looks like every time you launch the popup you bind a new click event to it. So if you launch the same popup twice you will have two on click event handlers bound to the object.
Accessing variables outside the closure is practical. However, you can only access the variables that has been defined before you define your closure.
Imagine that you move the definition of "ok" after you define your click event handler. In that case OK would not be defined and there will be another ok in the event handler.
(I hope I understood your question correct, please comment otherwise)
Try this:
var launchPopUp = function launchPopUp(ID) {
'use strict';
var popup = $('#popUp'), //cache #popup instead of doing multiple lookups
headData = 'SVG PopUp',
entData = 'Enter the data you want to store:',
submit = null, //declare a var to cache #btnSubmit instead of doing multiple lookups
submitHandler = function (e) { //handler can be defined anywhere in this routine
//collData should be defined in the handler
var collData = {
"ID": ID.id, // ID of the element or area clicked.
"header": headData,
"OK": "No",
"input": document.getElementById('txtData').value
};
//modify collData based on inputs at time #btnSubmit is clicked.
if (collData.input !== "") {
collData.OK = "yes";
$(ID).css('fill', 'green'); // Change colour to green only if some valid data is entered.
closePopUp();
}
collection.push(collData);
};
if (popup.is(':hidden')) {
popup.append(addHeader(headData));
popup.append(addEnterable(entData));
//if addButtons() defines/creates/adds #btnSubmit then you will need
//to attach the handler after #btnSubmit exists in the DOM
popup.append(addButtons());
//once #btnSubmit is in the DOM, you can add the handler at any time
//although I recommend doing it prior to showing #popup
submit = $('#btnSubmit'); //cache #btnSubmit
if (!submit.data('handlerAttached')) {
//only need to attach the handler one time.
//also note that attaching the handler does not fire the handler
//only clicking the button, or calling the handler (i.e., submit.click()
//or submitHandler(), etc.) will fire the handler.
submit.click(submitHandler);
//set flag to indicate that the handler has been attached.
submit.data('handlerAttached', true);
}
popup.show();
}
};
Also, as long as these are all defined elsewhere:
addEnterable()
addButtons()
addHeader()
closePopUp()
collection[]
your routine shouldn't have any errors preventing execution of the handler.
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
}