This is a fairly weird case, you can see the code here:
http://jsfiddle.net/zpZtH/2/
you should not wrap input elements by using a label element, try this:
<label for="average-data" class="section-view-time-checkbox">
<span class="custom checkbox checked"></span> Average
</label>
<input type="checkbox" id="average-data" style="display: none;">
http://jsfiddle.net/zpZtH/7/
http://jsfiddle.net/Cc55g/
You need to call event.preventDefault() within your click handler. This prevents the default click action from being executed once your custom function runs. The second alert is occurring because the form is being submitted.
This is a common Bug in Javascript. you can find many articles around internet specially on SO for event being fired twice. You can try something like this
$(document).on('click', '#task-list li', function(e)
{
alert('Hellow world');
e.stopPropagation();
return false;
});
And it's definitely Javascript problem because if you hit google and search for event fire twice you will see that Angular, Jquery and backbone etc all are somewhere firing events twice or even thrice. So, it's seems that it's javascript behind this. And off course if you search this with Mozilla Developers Network then you can see experts have also said so.
Related
I'm experiencing some (to me) unexpected behavior from event listeners using jQuery, but I expect it's just the underlying Javascript functionality that's confusing me. I think there's a good chance that the answer to my problem is fairly simple, but I can't figure it out.
I have a <div> with a status in it, which is 'New' by default. I want to be able to click on that <div> and bring up a pair of buttons, one which allow you to replace the 'New' status text with 'Complete', and another which will cancel the action, removing the buttons and displaying the 'New' status text again.
I can get everything to work, and it all works fine if I use a different element to display the buttons, but when I try to temporarily replace the text in the <div>, something strange happens.
When I try to reset the original click event for the <div>, what appears to happen is that the click on the cancel button also triggers the just-set click event as well. This re-displays the buttons, so it looks like the cancel button just didn't work. (I was stuck on that for a while...)
I've made a very simple JSFiddle that shows the problem I'm having:
https://jsfiddle.net/pn1q658w/4/
And there's also a slightly modified version that shows things working as long as I've got the cancel button in a different element than the element where I'm resetting the original click function:
https://jsfiddle.net/pn1q658w/3/
I assume this has something to do with the fact that I don't completely understand the way that the timing of these events works. The same click appears to be firing off an event that is set during an action taken because of that click, which I didn't expect, but may very well be how things are supposed to work.
My question is how can I have a click event which is trying to set a click listener on a parent element not fire off the new click at the same time?
Or, if I've completely misunderstood the nature of my mistake, an indication of what I have done wrong would be much appreciated. Thank you!
UPDATED
Just like #charlietfl said, I bleive that the simplest way is to separe the elements everyone with his own class, See WORKED FIDDLE HERE :
HTML :
<div id="elementId">
<span class='text'>New</span>
</div>
JS :
$(function(){
var newBtn = '<button class="btn btn-default complete">Complete?</button><button class="btn btn-default cancel">X</button>';
//Handle the click in the text span
$("#elementId").on("click","span.text",function(e){
$(this).html(newBtn);
});
//Handle the click in the complete button
$("#elementId").on("click","button.complete",function(e){
$('#elementId').html("<span class='text'>Completed</span>");
});
//Handle the click in the cancel button
$("#elementId").on("click","button.cancel",function(e){
$('#elementId').html("<span class='text'>New</span>");
});
});
I hope that this code help you.
The problem is you rewrite alaways content of div because you don't stop propagations.
I fix your problem with this code:
var oldCellContent = $('#elementId').text();
var newButtons = '<button class="btn btn-default complete">Complete?</button><button class="btn btn-default delete">X</button>';
$("#elementId").click(function(){
$(this).html(newButtons);
});
$("#elementId").on("click","button.complete",function(e){
console.log('The complete function fired.');
$('#elementId').text('Completed');
e.stopPropagation();
});
$("#elementId").on("click","button.delete",function(e){
console.log('The cancel function fired.');
$('#elementId').text(oldCellContent);
e.stopPropagation();
});
Need to understand that when you click on an element inside another element...you are still clicking on the parent as well.
Events "bubble" or "propagate" up the DOM tree all the way to the document...unless told to stopPropagation()
What you are seeing is expected behavior.
You can prevent that bubbling by:
$(selector).click(function(event){
event.stopPropagation();
});
There are some oddities in your code that could defintiely be streamlined
First you pass an element to the handler...then take properties of that elemnt to create a selector to find exactly the same element again in the DOM
var cellId = element.id;
$('#' + cellId)
Can be simplified to
$(element);// doesn't require searching for the ID
And can also be stored as a variable instead of doing the same selector over and over
var $el = $(element);
$el.off('click');
var oldCellContent = $el.text();
These simplifications are more efficient and easier to read
The simplest solution to all of this is wrap the "New" text in it's own element and put the "show buttons" click handler on that element and simultaneously hide "new".
Code will be much simpler and there won't be any propagation issues or need to use off() and then add same handler again.
I'm using the Knockout webmail tutorial as a template for a Single Page Application I'm working on.
However I'm having trouble implementing the click binder, I've had this sort of thing working before but his time the click events are being hijacked.
My view model has a function:
var self = this;
self.goToItem = function(item) { location.hash = "#/Item/" + item.id };
which is standard.
<h2>Saved Items</h2>
<div data-bind="foreach: savedItems">
<div data-bind="click: $root.goToItem">
<p data-bind="text: name"></p>
</div>
</div>
I've tried the:
<pre data-bind="text: ko.toJSON($root, null, 2)"></pre>
but, tellingly, this came back empty although the foreach has data to loop over.
The problem now is that the mousevent click is now caught by jQuery, I haven't had to delve into this before, but I am sure knockout runs without jQuery. At the moment the only jQuery I use is for the Ajax calls.
So where do I go to inspect the events on DOM objects, preferably in Chrome?
How can jQuery butt in?
Have you tried to use clickBubble binding?
Preventing the event from bubbling
By default, Knockout will allow the click event to continue to bubble up to any higher level event handlers. For example, if your element and a parent of that element are both handling the click event, then the click handler for both elements will be triggered. If necessary, you can prevent the event from bubbling by including an additional binding that is named clickBubble and passing false to it, as in this example:
<div data-bind="click: myDivHandler">
<button data-bind="click: myButtonHandler, clickBubble: false">
Click me
</button>
</div>
Normally, in this case myButtonHandler would be called first, then the click event would bubble up to myDivHandler. However, the clickBubble binding that we added with a value of false prevents the event from making it past myButtonHandler.
More details about click binding is here http://knockoutjs.com/documentation/click-binding.html
If I replaced
click: $root.goToItem
with
click: goToItem
it works again.
It seems the jQuery event firing was a red herring, I compared it to a working system and it started off in jQuery. I had to brush up on my DOM debugging, which is no bad thing.
Is the $root superflous, it took someone else to point this out to me. I was sure that in a foreach loop you could only access the $root functions via $root.
I'm really stuck with a jQuery issue and I hope someone can help me out...
So I have a list of options on the left, and when you click on one, a form is generated via Ajax on the right. There's this element in the form:
<input type="text" class="value" value="something">
And what I want to do is to call
$(".value").tagsInput();
which is a jQuery plugin that works pretty much like Stack Overflow's 'Tags' input field when you ask a question.
So I tried this:
$(document).ready(function() {
$(".value").on("load", function () {
console.log("Tags Input");
$(".value").tagsInput();
});
});
and nothing is printed out. I've also tried this:
$(document).on("change", ".value", function () {
console.log("Tags Input");
$(".value").tagsInput();
});
and it doesn't work either. I'm wondering where I did wrong. Can anyone help me out?
As pointed out by Shabnam, the "change" event is not what you want, as it is fired only once the field is blurred.
Anyways, from the plugin documentation, it looks like you don't have to call that function every time a key is pressed, but it attaches its own event handlers autonomously.
So, probably you should be fine with just:
$(document).ready(function() {
$(".value").tagsInput();
});
Your .on handler will never work, as the load event is fired only by document when the page is ready.
If you want to debug things a bit, have a look at the supported callbacks, such as onChange.
SIDE NOTE
I don't like how that plugin is written, as it clogs the "global" jQuery.fn namespace with lots of functions, while jQuery documentation recommends not doing so (see: Namespacing).
UPDATE
See here: http://jsfiddle.net/aFPHL/ an example of this working (the .load() was monkeypatched to avoid having to call an actual URL, but its behavior is pretty much the same as the real one).
"change" event gets fired when the input element loses focus. If you want ajax call at the end of each key input, try using keyboard events
I don't know what is wrong with that, because I was following at every step the tutorial from jquery.com regarding the form submit event.
My Javascript:
[Ofc. latest jQuery library is included].
<script type="text/javascript">
$("form#addFav").submit(function(event) { event.preventDefault(); alert("hello"); });
</script>
Have also tried with the $(document).ready() event:
$(document).ready(function(){
$("form#addFav").submit(function(event) { event.preventDefault(); alert("hello"); });
});
Here is my HTML form code:
<form action="" id="addFav">
<input type="text" name="name" class="thin-d"/>
<input type="submit" value="Send"/>
</form>
So, regarding the above Javascript code, it is supposed to work (I mean it should prevent default action [submitting form] and send the alert then), but it all doesn't work - have tried with thousands of combinations, but I fail'd. So I'm waiting for your solutions. I'd appreciate every one.
You probably have some syntax error or somthing like that somewhere else, because what you have just works.
Are you sure there aren't any JS errors?
P.S. I would alwyas go for the latter code to ensure that the elements are in the DOM before trying to attach events.
For anyone else who has the same problem, and still struggling to solve this issue, try to see if you have illegally reused the id, and try changing the form id to something unique.
I had accidentally given the id to two different DOM elements and the event was being bound to the first element with the respective id and my form was the second one so it was never captured. This had me pulling my hairs for quiet a long.
I just recently ran into the same issue. Jquery on submit would not work on the form, however just changing it to click event worked fine. Still at a loss why .on(submit) or .submit() events will not recognize the form.
$("form#addFav").click(function (event) {
event.preventDefault(); alert("hello");
$(this).submit();
});
this question is old but.. you might have had another submit events firing before yours fired. If these other events contained "return false;" statement then the event execution got interrupted and your code never fired. To put your code BEFORE these events you might use ONSUBMIT form attribute where you can put code that will fire before or at the same time as other events.
I'm having problems with .live() and confirm. It's multiplying the confirm dialogs for every click. I know about .die() but i can't get it to work.
$("button.del").live("click", function(){
if(!confirm("Are you sure?")) {
//close
}
});
I've tried $("button.del").die("click"); right after the above code, in which case the confim doesn't even fire.
Does the dialog box appear multiple times if you just run that code by itself?
If the dialog box is appearing multiple times, one likely explanation is that you are accidentally running this .live() binding more than once. If that happened, you would see one dialog box for each time you bound an event to the button.
Make sure you are only attaching this function to the button once.
If you take a look at this standalone example, you can see that your code is fine.
Can you post the HTML as well.
One cause I can speculate for this is that the .del class is specified into some child class, and the event is firing on both parent and child. This would happen for the following:
<div class="testclass">
test
<div class="testclass">
test2
</div>
</div>
...
$(".testclass").click(function() { alert("test"); });
Another reason would be if you accidentally bound it twice, i.e. the following would cause the same problem
$(".testclass").click(function() { alert("test"); });
$(".testclass").click(function() { alert("test"); });
We really need to see more of your code. You must utilise live for a reason. Do you get the same result with a simple click() binding?
Thank you all for your replies...turn out it was a bug in my code... Sorry...
I didn't see it... the part of the code with confirm was reloading on every click...hence the multiplying...