I have this HTML tag
<input type="file" id="File">
which has an event listener
document.getElementById("File").addEventListener("change", function() {alert("test")});
I would like to copy the function in the listener but all the following lines return null or undefined
document.getElementById("File").getAttribute("change")
//null
document.getElementById("File").change
//undefined
document.getElementById("File").getAttribute("onchange")
//null
document.getElementById("File").onchange
//null
How can I copy the anonymous function from the listener?
You can't.
You didn't keep a reference to it, and there is no API to pull it out of the list of listeners.
Refactor your code so you keep a reference to it from the start.
function myChangeHandler (event) {
alert("test");
}
document.getElementById("File").addEventListener("change", myChangeHandler);
As an alternative you could trigger the event of the original object with dispatchEvent(). But note, if the function uses this reference it will refer to the original element the event is attached to. Same is true if the event paramter is used (function(event){}).
document.getElementById("test").addEventListener("change", function() {
console.log("test");
console.log("triggered element id: " + this.id);
});
document.getElementById("manual").addEventListener("click", function() {
document.getElementById("test").dispatchEvent(new Event('change'));
});
<input id="test">
<button id="manual">manual</button>
Another alternative is to overwrite the standard addEventListener() function so it will store a reference to the given function. This is an example of this. You probable want to store the reference in a different way but kept it easy as an example.
You only have to make sure that the function is overwritten before the element is created.
//Store the orignal addEventListener() function under a new name so we can still use it.
Node.prototype.originalAddEventListener = Node.prototype.addEventListener;
//Create a variable where we store the handler for the #test1 element
var test1Handler;
//overwrite the orignal function with our own so it will store a reference to the #test1 event handler in the variable
Node.prototype.addEventListener = function(e, fn){
if(this.id === 'test1') {
test1Handler = fn;
}
this.originalAddEventListener(e, fn);
}
//Attach event with the overwritten function, lets say this is done by an extarnal libary.
document.getElementById('test1').addEventListener('change', function(){
console.log("Changing element id: " + this.id);
});
//When the button is clicked the change handler of test1 is copied to test2.
document.getElementById('exec').addEventListener('click', function(){
document.getElementById('test2').addEventListener('change', test1Handler);
});
<label for="test1">Test 1</label><input id="test1"><br>
<button id="exec">Add Test 1 change handler to Test 2</button><br>
<label for="test2">Test 2</label><input id="test2"><br>
If you want to do this for the window object you probably need to overwrite window.addEventListener because window isn't a Node
Related
I'm using JQuery inside EcmaScript 6 class, and I have an event function which fires on instantiation of the class and the event contains different JQuery events which need to interact with the Class , so I do .bind() to achieve that, all works ok except one event which for some reason overrides this that belongs to jquery element "this" with "that" which I passed with .bind(that) method, here is my code (everything works exept for this event) :
var that = this;
$(document).on('click', '[select-file]' , function(event) {
event.preventDefault();
console.log(this);
}.bind(that));
so the console log gives me the parent class instead of jquery element
where as this works as expected:
$(document).on('click', '[open-file-dialoge]', function(event) {
event.preventDefault();
$('[file-dialoge]').modal('show');
if ($(this).attr('mitiupload') == 'false') {
// check if multiple upload is disabled
that.multiUpload = false;
$(this).removeAttr('multiple');
}
that.insertFiles();
}.bind(that));
Pleas help , I can't understand what is going on here one does not work as expected even though there is no big difference between them ;(
Function#bind() changes the context of this in a function. If you want the current element you can use event.currentTarget
var that = {};
$(document).on('click', 'button', function(event) {
event.preventDefault();
var el = event.currentTarget;
console.log('this=', this);
console.log('el=', el)
}.bind(that));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="test">Click me</button>
I'm new to ES6, and can't quite get this to work:
$(this) returns undefined on click?
dom.videoLinks.click((e) => {
e.preventDefault();
console.log($(this));
var self = $(this),
url = self.attr(configuration.attribute);
eventHandlers.showVideo(url);
// Deactivate any active video thumbs
dom.videoLinks.filter('.video-selected').removeClass('video-selected');
// Activate selected video thumb
self.addClass('video-selected');
});
However if I change it so not be an arrow function like so, it works as expected?:
dom.videoLinks.click(function(e) {
e.preventDefault();
console.log(this);
console.log($(this));
var self = e.this,
url = self.attr(configuration.attribute);
eventHandlers.showVideo(url);
// Deactivate any active video thumbs
dom.videoLinks.filter('.video-selected').removeClass('video-selected');
// Activate selected video thumb
self.addClass('video-selected');
});
So how would I go about it if I use an arrow function in the callback?
With arrow function as a callback, instead of using this to get the element to which the handler is bound, you should use event.currentTarget.
Value of this inside an arrow function is determined by where the arrow function is defined, not where it is used.So from now on, keep in mind that
event.currentTarget always refers to the DOM element whose EventListeners are currently being processed.
.currentTarget vs .target
Use event.currentTarget instead of event.target because of event bubbling/capturing:
event.currentTarget- is the element that has the event listener attached to.
event.target- is the element that triggered the event.
From the documentation:
currentTarget of type EventTarget, readonly Used to indicate the
EventTarget whose EventListeners are currently being processed. This
is particularly useful during capturing and bubbling.
Check the basic example in the below snippet
var parent = document.getElementById('parent');
parent.addEventListener('click', function(e) {
document.getElementById('msg').innerHTML = "this: " + this.id +
"<br> currentTarget: " + e.currentTarget.id +
"<br>target: " + e.target.id;
});
$('#parent').on('click', function(e) {
$('#jQmsg').html("*jQuery<br>this: " + $(this).prop('id')
+ "<br>currenTarget: " + $(e.currentTarget).prop('id')
+ "<br>target: " + $(e.target).prop('id'));
});
$('#parent').on('click', e => $('#arrmsg').html('*Arrow function <br> currentTarget: ' + e.currentTarget.id));
#parent {background-color:red; width:250px; height:220px;}
#child {background-color:yellow;height:120px;width:120px;margin:0 auto;}
#grand-child {background-color:blue;height:50px;width:50px;margin:0 auto;}
#msg, #jQmsg, #arrmsg {font-size:16px;font-weight:600;background-color:#eee;font-family:sans-serif;color:navy;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="parent">Parent-(attached event handler)<br><br>
<div id="child"> Child<br><br>
<p id="grand-child">Grand Child</p>
</div>
</div>
<div id="msg"></div><br>
<div id="jQmsg"></div><br>
<div id="arrmsg"></div>
You wouldn't.
Changing the value of this is the primary point of using an arrow function.
If you don't want to do that then an arrow function is the wrong tool for the job.
You can use $(event.target) instead of $(this) even inside of an arrow function. Arrow functions are preserving this of the scope where they were defined. In your case it is undefined.
arrow functions and this selector?
Arrow functions retain this from enclosing context.
Eg.
obj.method = function(){
console.log(this);
$('a').click(e=>{
console.log(this);
})
};
obj.method(); // logs obj
$('a').click(); // logs obj
So how would I go about it if I use an arrow function in the callback?
You already can - to access event target you can use something like $(e.target), but beware of bubbling. So I recommend to use normal functions instead as callbacks.
I'd like to dynamically create event listeners for multiple buttons, and subsequently, show a particular frame label depending on the button clicked, but I'm unsure what to pass through (FYI, this is will be used for HTML5 canvas in Flash CC, but principally the same should apply to a web page for showing divs etc). I currently have this:
var butTotal = 4;
var selfHome = this;
function createListeners () {
for (var i=0; i<butTotal; i++) {
selfHome["btn" + i].addEventListener('click', openPop);
}
}
function openPop () {
alert("test");
selfHome.gotoAndPlay("pop"+event.currentTarget.name.substr(3));
}
createListeners();
It creates the listeners fine, but I don't really know where to start with passing through the current button instance name to tell it which frame label to gotoAndPlay.
Based on the code that you have, I'd simply change the .addEventListener() to call a generic function (rather than openPop, directly), and pass it the reference to the button. So, this:
selfHome["btn" + i].addEventListener('click', openPop);
. . . would become this:
selfHome["btn" + i].addEventListener('click', function() {
openPop(this);
});
At that point, you would then have to update openPop to accept a parameter for the reference to the element that triggered it . . . something like:
function openPop (currentButton) {
At that point, you could reference the clicked button, by using currentButton in the openPop logic.
I'm not sure I totally understand your question. However if you just need to pass the button instance (in you case "selfHome["btn" + i]") you could call an anonymous function in your event handler which calls openPop() with the button instance as an arugment. Would this work for you?
var butTotal = 4;
var selfHome = this;
function createListeners () {
for (var i=0; i<butTotal; i++) {
var currentBtn = selfHome["btn" + i];
currentBtn.addEventListener('click', function(){openPop(currentBtn);} );
}
}
function openPop (btn) {
alert("test");
selfHome.gotoAndPlay(/*use button instance 'btn' to find frame*/);
}
createListeners();
When the event is triggered the this keyword inside the handler function is set to the element is firing the event EventTarget.addEventListener on MDN. If the button have the data needed to be retrieved just get it from the this keyword:
function openPop (btn) {
alert(this.name);
/* ... */
}
It looks like you expect it to contain the function gotoAndPlay() as well as the btn elements (which contain both an ID (of btn[number]) and a name with something special at substr(3) (I assume the same as the id). If those things were all true, it should work in chrome... in other browsers you'll need to add event to the openPop() method signature.
function openPop (event) {
alert("test");
selfHome.gotoAndPlay("pop"+event.currentTarget.name.substr(3));
}
I believe this is what you are looking for and adding that one word should fix your problem (assuming some things about your dom and what selfHome contains):
JSFiddle
You could also leave out the event from openPop() and replace event.currentTarget with this:
function openPop () {
alert("test");
selfHome.gotoAndPlay("pop"+this.name.substr(3));
}
JSFiddle
I want to create a function and then use with onclick method, for example:
one = document.getElementById("oneID");
then instead of writing function for each onclick():
one.onclick = function(x) {
tempStack.push(parseFloat(one.value));
viewTemp.value += one.value;
}
I want to use a single function:
one.click = input(one);
but I'm not sure how to do it in the correct way for example the below I tried, doesn't work:
var input = function(x) {
tempStack.push(parseFloat(x.value));
viewTemp.value += x.value;
}
Lastly, no external JavaScript libraries to aid this question, vanilla JavaScript.
You'll need to pass a function as a reference, not call it:
one.onclick = input;
In this case you won't be able to pass an argument, but you can use this as a reference for the DOM element on which event is fired:
function input() {
tempStack.push(parseFloat(this.value));
viewTemp.value += this.value;
}
Here's a method with using JavaScript's .addEventListener(), as a previous answer mentioned, using this to pass through the DOM Node Element to use within the inputFunction.
<input type="text" value="64.23" id="bt" />
<script>
function inputFunction( x ) {
console.log( x.value ); //Console Logs 64.23
}
var bt = document.getElementById("bt");
bt.addEventListener( 'click', function(){ inputFunction( this )}, false );
</script>
Fiddle: http://jsfiddle.net/Lhq6t/
Think about functions as a normal objects, so the way is:
function input (event) {
// Process the event...
// event is my event object
// this is the object which trigger the event
// event.target is my button
}
on.onclick = input;
You must assign the input function as a normal variable.
The function input will receive an event object as parameter. Also you can refer to the button clicked with this.
Maybe the mozilla developer network or the real w3c site would explain it better.
Your requirement can be achieved by following:
Add this method in your script tag:
function input(x) {
/*tempStack.push(parseFloat(x.value));
viewTemp.value += x.value;*/
alert(x.id);
}
And then call this method onClick event of your buttons / anchors like:
<input type="button" id="oneID" value="oneID" onClick="input(this);"/>
<input type="button" id="twoID" value="twoID" onClick="input(this);"/>
threeID
See working example: http://jsfiddle.net/Avd5U/1/
ok, so just create a function with a parameter in it like:
function setValue(input){
tempStack.push(parseFloat(input.value));
viewTemp.value += input.value;
}
and then call the function on the click of that element like:
var one = document.getElementById("oneID");
one.click = setValue(one);
Good luck!
I am using the SnackJS API. And I need to attach an event to each input element (Textbox) with the class name of "qty". I am not able to use the id attribute for this, as it is dynamically generated and unique, and is being used by something else:
<script type="text/javascript">
snack.ready(function () {
// Do your work.
// Attach an event to QTY Textbox elements.
var listener = snack.listener({
node: document.getElementsByClassName("qty"),
event: 'blur'
}, function () {
alert("hello, element.");
});
listener.detach();
listener.attach();
});
</script>
How do I use getElementByClassName?
You can either loop over the NodeList that getElementsByClassName returns (calling snack.listener each time you go around the loop), or delegate the event handler as per the API documentation:
var params = {
node: document.body,
event: 'click',
delegate: function (node){
return node.getElementsByClassName('qty')
}
}
snack.listener(params, someFunction);
getElementByClassName returns an array-like structure. You should loop through them and bind the event that way.