I've got a strange problem on Firefox that seems not to happen on Safari.
There's a table with a set of rows, each one of which has it's own onclick and ondblclick events. When one of the objects is double-clicked, it fires first the onclick associated function (as expected), where another row (different from the one double-clicked) is deleted. Afterwards, the function associated with dblclick won't fire.
If I comment the line which removes the row (not the one clicked, as I said, but another one), then both the onclick and ondblclick events will fire... I attach you the code for both event functions:
ret.onclick = function(){
// Trigger click event
var evt = arguments[0] || window.event;
self.signalClick(evt.target || evt.srcElement);
if(elem == this.selected) return;
if(self.selected != null){
// Set list element to not selected
var telem = document.getElementById(self.getChildID(self.selected['id']));
telem.setAttribute('class', 'gui_list_uselected');
// Remove previously selected element summary
var telemexp = document.getElementById(self.getChildID(self.selected['id']) + '_exp');
if(telemexp) telemexp.parentNode.removeChild(telemexp); // FAULTY LINE!
}
ret.setAttribute('class', 'gui_list_selected');
self.selected = elem;
// Add element summary to the list
appendAfter(ret, self.drawSummary(elem));
};
ret.ondblclick = function(){
// Trigger double click event
var evt = arguments[0] || window.event;
self.signalDblClick(evt.target || evt.srcElement);
};
Firefox works correctly. According to the spec, onclick fires before ondblclick anyway.
Check out this so answer to overcome that.
Related
I have an HTML page that is partially generated by a 3rd party that I cannot change. However, I can add my own Javascript to the page to modify it's behavior.
I want to remove a keypress event listener from an input textbox.
In Chrome dev tools, if I view the element, I can see the following two events tied to a keypress:
I added the second event listener with the following code:
$('#signInName').keypress(function (e) {
var key = e.which;
if(key == 13 && $('.sendCode').css('display') != 'none')
{
$('.sendCode').trigger('click');
return false;
}
});
I want to remove the first listener in the image. If I click the 'remove' button in dev tools I can confirm that I get the functionality I want, which is to click a different button when I press ENTER, than what the 3rd party has set to fire.
I can see that I can get access to the events using this jquery:
> $('#signInName').keypress.length
< 2
But, I am very limited in my JQuery or javascript experience, and I want to remove the event listener as mentioned.
How can I reference and remove this other event listener preferably using a static identifier and without using the exact index of 0 in the collection, which might change?
Name the function:
signInNameKeypressHandler = e => {
var key = e.which;
if(key == 13 && $('.sendCode').css('display') != 'none')
{
$('.sendCode').trigger('click');
return false;
}
}
$('#signInName').keypress(signInNameKeypressHandler);
//later
$('#signInName').off('keypress', signInNameKeypressHandler);
You can use remove removeAttr for removing first event listener before defining your event listener.
$("#signInName").off("keypress");
$('#signInName').keypress(function (e) {
var key = e.which;
if(key == 13 && $('.sendCode').css('display') != 'none')
{
$('.sendCode').trigger('click');
return false;
}
});
There are 5 buttons where each button will do a different thing.
The first button will change a paragraph to green (in HTML file, Id="button1").
The second button will change a paragraph to blue (in HTML file, Id="button2").
window.onload = pageLoad;
function pageLoad() {
this.onclick = makeChange;
}
function makeChange() {
var paragraph = document.getElementById("paragraph");
if (this.id = "button1") {
paragraph.style.color = "green";
} else {
// change the color
}
}
This doesn't work because I can't get the id of the button, I tried to debug it using:
paragraph.innerHTML = this.id;// I got "undefined"
Is there anyway I can get which button is pressed, and based on which button is pressed, change the text color differently? I want to use only 1 function(exclude pageLoad) to do this and I don't to have 5 variableS and 5 onclick lines and no jquery.
var paragraph = document.GetElementById("button1");
var paragraph = document.GetElementById("button2");
var paragraph = document.GetElementById("button3");
....
You could try something like this. Keep the color you want to change the paragraph to inside the button, using a custom data-* attribute. Then access it with .getAttribute(). So your JS would be something like this:
function makeChange() {
var paragraph = document.getElementById("paragraph");
var newColor = this.getAttrbiute('data-color');
paragraph.style.color = newColor;
}
And your buttons would be like this:
<button data-color="green">Green</button>
<button data-color="blue">Blue</button>
This way you can easily change the target color by changing the data-color attribute.
As a side note, do make sure you're listening for the click event with your buttons, like this:
var buttons = document.querySelectorAll('button');
for (var i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', makeChange);
}
Using an event listener to leverage Event Delegation has a few advantages over an on event (ex. onclick) property or attribute event handler:
Unlike on event handlers, event listeners can be used multiple times on multiple objects and elements.
By setting the 3rd parameter to true, you can listen for events in capture phase. It's rarely needed.
We can setup a pattern to take advantage of the 3 Event.eventPhases:
Capture: Starting from Event.currentTarget (ex. #set) the event chain goes down the DOM tree to the end of this phase is...
Target: The element that is the origin of the event is the Event.target (ex. #btn*).In simpler terms, e.target is the element clicked, checked, changed, etc. This element will be the context related to the event, in many ways e.target is like this (in this demo, e.target is one of the buttons and this is the ancestor (fieldset#set, e.cT)...
Bubbling: This is the phase after the callback is initiated and the event chain reverses its path back up to the Event.currentTarget. On its way up, should there be any other elements registered to this particular event would also be triggered. This may be an unwanted behavior depending on the developer's intentions and circumstances. For those cases, Event.stopPropagation() can be called (usually placed as the last statement in the callback). Upon reaching the end of the bubbling phase, the e.cT calls the callback (this callback will be in the context of e.target, this context allows us to identify the clicked button)
Event Delegation is a process in which we setup our event listener on a higher level in the DOM (an ancestor element), then at target phase the clicked button will be identified by referencing e.target. This gives us a powerful and eloquent way to handle an unlimited amount of elements with a single event listener. No on event handler is capable of doing this under normal circumstances without the use of specialized interface.
More details are commented in demo
Demo
/* Reference an ancestor element of all the buttons.
|| In this case the best choice would be
|| fieldset#set. You could also use <body>, document,
|| or even window, but the further the ancestor is,
|| the chances of unwanted behavior from other elements
|| become greater.
*/
var set = document.getElementById('set');
/* Register #set on the click event.
|| Now #set is considered the Event.currentTarget.
|| The e.cT (#set) will listen for the event (click)
|| to occur upon itself and any of its decsendants.
|| Once event occurs, #set (e.cT) will run the
|| callback function (findBtn).
*/
set.addEventListener('click', findBtn, false);
/* This is the callback function which is a normal
|| function that is called when a registered event
|| happens.
*/
function findBtn(e) {
// An array of 5 colors
var rainbow = ['purple', 'blue', 'green', 'yellow', 'red'];
// Reference to the paragraph (<p>)
var text = document.querySelector('p');
/* if e,target (the element clicked), is NOT
|| e.cT, then...
*/
if (e.target !== e.currentTarget) {
/*...and if e.T (Event.target) tagName is
|| 'BUTTON', then...
*/
if (e.target.tagName === 'BUTTON') {
// ...get the button's #id
var tgtID = e.target.id;
/* The id of each button is basically just
|| an index number. Although I do not
|| recommend it normally, it is valid to start
|| with a number for an #id.
|| This statement uses the style property to
|| access the paragraph's CSS color property
|| and changes the value according to the
|| index of the rainbow array which in turn is
|| determined by the e.T (button clicked) #id
*/
text.style.color = rainbow[tgtID];
}
}
// End function
return false;
}
<fieldset id='set'>
<legend>Event Delegation</legend>
<button id='0'>Purple</button>
<button id='1'>Blue</button>
<button id='2'>Green</button>
<button id='3'>Yellow</button>
<button id='4'>Red</button>
</fieldset>
<p>Click any of the five buttons to change this text.</p>
I'm trying to add a click listener to the document when a dropdown is open, so that when you click anywhere else in the document it closes the dropdown and unbinds the click listener. I'm using some code from https://stackoverflow.com/a/17342418
I've discovered an issue though.
Binding:
$(document).bind('click', $scope.remindersDropdownHandler(event));
Handler:
$scope.remindersDropdownHandler = function(event) {
var element = $("#remindersDropdown");
var isClickedElementChildOfPopup = element
.find(event.target)
.length > 0;
var buttonElement = $("#remindersButton");
var isbuttonElement = buttonElement
.find(event.target)
.length > 0;
if (isClickedElementChildOfPopup || isbuttonElement) {
return;
}
$scope.openReminders = false;
// $(document).unbind('click', $scope.remindersDropdownHandler);
}
The handler itself is working just fine, however it only ever executes once! And that's immediately when you click the button that opens the drop-down and adds the bind. After that no matter where you click it never fires the listener again. (Trust me I've done a lot of debugging with console.log() over the past hour.)
However, if instead of referencing a function for the handler, I instead write it like such:
$(document).bind('click', function() {
var element = $("#remindersDropdown");
var isClickedElementChildOfPopup = element
.find(event.target)
.length > 0;
var buttonElement = $("#remindersButton");
var isbuttonElement = buttonElement
.find(event.target)
.length > 0;
if (isClickedElementChildOfPopup || isbuttonElement) {
return;
}
$scope.openReminders = false;
});
That works, and each time I click somewhere on the document it correctly executes the handler and closes the drop-down. The problem is because I haven't referenced the handler via a variable, I can't unbind it, so the handler is permanently attached. I need to be able to unbind it so that my site doesn't get overloaded with click listeners on the document.
So my issues are:
1) When I reference $scope.remindersDropdownHandler() as the handler for my click listener, why does it only fire once and then never again?
2) How can I fix up my code so that I bind the appropriate function for the click listener, and then unbind it when I choose to do so?
Note: In the example code I'd commented out the // $(document).unbind('click', $scope.remindersDropdownHandler); just to reinforce that there was no code that was immediately unbinding my click listener.
Solved: A user on Reddit pointed out that removing (event) from the specified handler in the bind would allow it to work.
https://www.reddit.com/r/angularjs/comments/3fypck/help_issue_with_binding_and_unbinding_a_click/cttr0bw
I.e. converting
$(document).bind('click', $scope.remindersDropdownHandler(event));
to
$(document).bind('click', $scope.remindersDropdownHandler);
I have a script that reloads an iframe whenever the browser screen is clicked (works perfectly). I was wondering how I would go about disabling the javascript from running on certain links?
Here is my current script:
document.onclick= function(event) {
if (event===tichack) event= window.event;
var target= 'target' in event? event.target : event.srcElement;
document.getElementById("tichack").src = "http://link.com?"+(+new Date());
};
Example would be something like this i suppose? (obviously incorrect) but will give you a better idea of what I am trying to achieve, did allot of searching but have had no luck?:
onclick="javascript:disabled=true;"
Basically, you need to identify what the target of your click is and, if the target is equal to one of the links you don't want triggering this, return from the function without refreshing the iframe.
var links = /* a collection of elements you don't want triggering the iframe refresh */,
count = links.length,
i;
for (i = 0; i < count; i += 1) {
if (target === links[i]) {
return;
}
}
There's two ways:
in the document.onclick, check the target element if it's a certain link, and then don't do anything. I.e. if (target.id == '...') { return; }
make sure that the click never arrives at the document.onclick. Because of how the DOM Event model works, if you cancel an onclick event at a low level (i.e. at a link itself) it will not bubble up and arrive at the document.onclick. So the following code works:
<a href='...' onclick='return false;'>click here!</a>
See http://bitovi.com/blog/2010/10/a-crash-course-in-how-dom-events-work.html for more information on the DOM Event model!
You can do this:
document.onclick = function (event) {
event = event || window.event;
if (event.target.id != 'tichack') return;
document.getElementById("tichack").src = "http://link.com?" + (+new Date());
};
Here, the document click event will work for the tichack link only.
SIMPLE DEMO HERE
So, what I want is basically to attach a javascript handler to a form, that whenever one of the form input boxes / select boxes is changed or clicked on, this handler would be called with the id of the element that was changed.
The reason I was wondering about this is because I already have this form that has about 50 input boxes, and I need to append text into a different text box each time an action occurs on any of the 50 input boxes. I know this could be done by attaching a function to each of the 50 text boxes but it seems like there should be an easier way?
You could bind to the keydown/keyup events on the form, and then look at the srcElement or target to find out which input was actually modified. I don't think you can use change on a form element though.
Basically:
function Bind() {
var obj = document.getElementById("myForm");
if (obj.addEventListener)
{
obj.addEventListener("keyup",Process,false);
obj.addEventListener("keydown",Process,false);
}
else if (obj.attachEvent)
{
obj.attachEvent('onkeyup',Process);
obj.attachEvent('onkeydown',Process);
}
}
function Process(e) {
if (!e) var e = window.event;
var src;
if (e.target)
src = e.target;
else if (e.srcElement)
src = e.srcElement;
// src now points to the input that was modified.
}