jQquery: change event fires even when it should not - javascript

I am building an application where ID are generated and the after AJAX call is done, the ID is appended to input as it's value. When this happens, the 'change' event is fired by calling .trigger('change') on the input. The code that does this is as follows:
$('form.card').each(function(index, element) {
$.ajax({
url: 'save-content.php',
method: 'POST',
data: $ajaxData,
success: function(returnData){ // the ID is received as 'returnData'
if ($create) { $(element).children('input[name=id]').val(returnData).trigger('change');
//ID added as input value and 'change' event is triggered
}
}
});
});
I use a jQuery File Upload plugin. Every time a file is done uploading, the 'done' event is triggered on each file. Since the ID is received via ajax, the script checks if there is any value, and if not, it attaches an event listener for input 'change'. The code is as follows (including the part from jQuery File Upload plugin):
$('form.fileupload').fileupload({
//some plugin setup
done: function (e, data) {
//get the input from sibling form (that is the input the 'change' event is triggered on (as described in the previous code))
$id = $(this).siblings('form.card').children('input[name=id]');
//if the input has value, do AJAX imediatelly, else wait for id 'change' event to be triggered
if($id.val()) {
//do the AJAX magic now
}
else {
//when 'change' event is fired, do the AJAX stuff
$(document).one('change', $id, function() {
//'change' event fired, do the AJAX magic
});
}
}
});
And now the problem: the change event in the second code is received even when it was triggered on other input[name=id] (from another form.card which has its own input[name=id]). Let me explain that: the first code is ran on each form.card, each having its own input[name=id] which the event is triggered on when ID from AJAX is appended. Then, when we upload the file from jQuery File upload plugin (which can be ran on multiple form.fileupload), the done event fires, registers listener for change event. And when you upload the file from let's say third form.fileupload, the event listener from the third form.fileupload done event catches change even from the first form.
And that has been driving me crazy for 2 days now. I have checked the objects that the event is triggered on and listener for: they're the same.
So what I need is the event listener attached to input[name=id] in third form.card to catch only change event from the input[name=id] in third form.card, not the first.
EDIT: Here is a fiddle of my problem: http://jsfiddle.net/yjnoaye2/3/ Timeouts added to mimic AJAX response delay.

As I stated in the comment it looks like you have event propagation issue.
you can learn about it here:
https://developer.mozilla.org/en-US/docs/Web/API/Document_Object_Model/Examples#Example_5:_Event_Propagation

I think you can add a namespace to your own event, such that only your listener will hear it.
trigger('change.myCustomChangeEvent')
...
$(document).one('change.myCustomChangeEvent', $id, function() {
See the section on namespaces here:
http://api.jquery.com/on/

OK, I have it now. The problem was, that the event listener was created on document and not the form.card that the input[name=id] is in. Even I have scpecified the exact object in the selector parameter, the event listener was attached to every input[name=id].
So all I needed to do was to change this:
$(document).one('change', $id, function() {
//'change' event fired, do the AJAX magic
});
to this
$(this).siblings('form.card').one('change', $id, function() {
//'change' event fired, do the AJAX magic
});
This way, the event listener is attached to particular input in particular form.card.
Here is a working fiddle: http://jsfiddle.net/yjnoaye2/5/

Related

How can I intercept the tweet button click event?

I'm developing a browser extension and I want to intercept the tweet button click event, just like in the image below:
I managed to get the element node like this:
document.querySelector('div[data-testid="tweetButton"]')
This is what I tried to do:
Override the node's "click" and "onclick" function
Override the node's "click" event listener, i.e. tweetButton.addEventListener("click", function() {})
Remove the "click" event listener, i.e. tweetButton.removeEventListener("click", function() {})
Repeat #1, #2 and #3 for "mousedown" and "onmousedown"
Add a global listener via document.addEventListener and check against a selector. The callback gets fired but the XHR still goes through, even if I did event.preventDefault() and event.stopImmediatePropagation().
Maybe it's not this object that the event listener is attached to, but in HTML it has the "button" role, so it should be the one.
Could I achieve the same goal by listening to the Ajax request?
After all, it seems solution #2 was correct:
let tweetButton = document.querySelector('div[data-testid="tweetButton"]');
tweetButton.addEventListener("click", function(event) {
event.preventDefault();
event.stopImmediatePropagation();
});
You can find here the open-sourced code.

PolymerJS: Multiple events fire for same action (on-blur when on-submit)

I have this input form and I want to save the value of the input whenever the user either fires an on-submit or an on-blur event.
And I have the problem, that whenever the user fires the on-submit, naturally the on-blur event is also fired. Thus two events with the same content is fired. (Not a big problem, but still).
I've searched for solutions and found a lot for jQuery, and I believe that I need a raw javascript solution for this.
Here is my form:
<form method="post" on-submit="doneEditAction">
<input
type="text"
value="{{editValue::input}}"
id="editItemInputField"
on-keyup="editKeyupAction"
on-blur="editBlur">
<button type="submit">edit</button>
</form>
This form fires the doneEditAction event when I submit the form. But at the same time the editBlur event gets also fired, which should do the same as the doneEditAction event, to save the value of the input.
editBlur Event
editBlur: function (e) {
this.doneEditAction(e);
this.editing = false;
}
doneEditAction Event
doneEditAction: function (e) {
e.preventDefault();
console.log(this.editingValue);
this.editing = false;
}
HERE ARE MY QUESTIONS:
How do I make the form not fire the on-blur event, when the form is submitted? Or
How do I make the form fire always only one event? Or, see edit,
Does it even matter at all (from a performance perspective) if two identical events are fired?
EDIT
Just saw that the Polymer TodoMVC and they also fire two events when you try to edit it. Proof:
Does that mean, that it actually doesn't matter, if two same events are fired?
Since the on-blur event fires automatically everytime the on-submit event is fired, the doneEdit event handler is executed twice.
And since the doneEdit event handler sets the editing property to false twice, there is a simple solution to make sure the doneEdit event is executed only once.
In doneEdit we check if the editing is true and only then perform any action we want, setting the editing value to false.
doneEdit(function) {
if(this.editing === true) {
this.editing = false;
console.log(this.editingValue);
}
}
Thus when the doneEdit handler will be called the second time due to the on-blur event, this.editing is already set to false and console.log() is not executed twice.
Thanks to the PolymerTodoMVC source code.

Trigger jQuery handler if search field contains "pre-populated" value

I have a search field that currently has an .on('input') event handler attached to it. However, in some instances the search field may be pre-populated if a value is passed through the URL (http://127.0.0.1/search/query-is-here). The issue here however is that the event handler will not be fired until the user edits the search field's value, meaning no search is automatically made.
I have tried initiating a .trigger by specifying focus, click, change, ... but none seem to work (and yes, I do change the event handler to .on('input focus') for example). What's the crack?
--
JS File (referenced in the footer BEFORE the trigger)
$('#search').on('input focus', function(e) {
e.preventDefault();
// various if statements and variable assignments
}
Trigger
// codeigniter -> http://ip.com/{segment 1}/{segment 2} -> this does get executed
<?php if($this->uri->segment(1) == "search" && $this->uri->segment(2)):?>
<script>
$('#search').focus();
$('#search').trigger("focus");
</script>
<?php endif; ?>
My understanding of $('#search').trigger("focus"); is that it should fire the event handler attached to #search, and execute the JS within that function.
You're subscribing to the event 'input focus' and triggering the event 'focus'. I think you'll want to subscribe to both events.
$('#search').on('focus', myHandler);
$('#search').on('focus input', myHandler);
Why are placing e.preventDefault() on focus? The event.preventDefault() method stops the default action of an element from happening.
Remove that e.preventDefault() from the code and try it again.
$('#search').on('input focus', function(e) {
//remvoe this line>> e.preventDefault();
// various if statements and variable assignments
}
Below is the jsfiddle link:
https://jsfiddle.net/shrawanlakhe/c8v5v788/1/
I have also place e.preventDefault() on the handler and it is preventing click event handler from firing .So first try it and the click event handler will not fire and then remove the e.preventDefault() and then try it again in the fiddle and this time event handler will fire

Why is event e undefined in callback when firing event manually?

I am using Mootools and adding a click event to a link. I have added a function to an event with this:
$('addCallRoute').addEvent('click', addCallRoute); // Add button
The function contains this:
function addCallRoute(e) {
console.log(e);
}
The function that fires the event (without an actual click)
$('addCallRoute').fireEvent('click');
The Problem:
When I click on the link physically, e is defined. but when I programmatically fire the event, e is undefined. Why?
Because you're not actually/physically triggering an action but firing it remotely. This is how it works.
event normally contains all sort of information about the element from which the action was triggered.
Always check if event is defined before trying to use any methods on it. Or do this:
link.fireEvent('click', {
stop: function(){}
});

Jquery remove and add back click event

Is it possible to remove than add back click event to specific element? i.e
I have a $("#elem").click(function{//some behaviour});, $(".elem").click(function{//some behaviour});(there are more than 1 element) while my other function getJson is executing I'd like to remove the click event from the #elem, and add it again onsuccess from getJson function, but preserve both mouseenter and mouseleave events the whole time?
Or maybe create overlay to prevent clicking like in modal windows? is that better idea?
edit :
I've seen some really good answers, but there is one detail that I omitted not on purpose. There are more than one element, and I call the click function on the className not on elementId as I stated in the original question
Rather than using unbind(), which means you'll have to rebind the same event handler later, you can use jQuery's data() facility with the ajaxStart and ajaxStop events to have your elements ignore click events during all AJAX requests:
$(".elem").click(function() {
if (!$(this).data("ajaxRequestPending")) {
// some behaviour
}
}).ajaxStart(function() {
$(this).data("ajaxRequestPending", true);
}).ajaxStop(function() {
$(this).removeData("ajaxRequestPending");
});
EDIT: This answer is also id-to-class-proof (see questioner's edit), since everything matching the selector will handle the AJAX events the right way. That's the main selling point of jQuery, and it shows.
You are looking for .unbind(). Pass it 'click' and it will destroy the click event.
I would put it just before your getJSON and re-bind the click event inside the success handler of your ajax call.
You have to do some additional scripting. There is no callback for that. Take a look over here: jQuery - How can I temporarily disable the onclick event listener after the event has been fired?
Rather than unbinding/binding the click event, you could check the state of another variable to see if it should do the action.
var MyObject = {
requestActive = false;
};
function MyJsonFunction() {
// when requesting
MyObject.requestActive = true;
//...
// when request over
MyObject.requestActive = false;
}
$("#elem").click(function{
if (MyObject.requestActive == true) {
//do something
}
});

Categories