I am utterly confused by this peice of code, that does not seem to work in any way.
Simply, it's this:
// in app.js
import {layoutItemButtonClick} from '/blablaWrappeur.js'
document.addEventListener('DOMContentLoaded', function () {
var element = document.querySelector('.qq-element') //this is a html element obj
$('.layout-item-button').click(layoutItemButtonClick)
})
//in blablaWrappeur.js
export const layoutItemButtonClick = function () {
const selectedLayout = this.dataset.layout.split("")
doQqthing(element) // element is not defined
}
function doQqthing(element) {
alert(element) /// not defined
}
I need to pass the element and the this context of the clicked button to the layoutItemButtonClick function and then inside that, to the doQqthing function.
However, it does not work like this.
1) If I let the code like this and click the button nothing happens.
2) Now, if I change the click function to this (adding paranthese to the function call:
$('.layout-item-button').click(function () {
layoutItemButtonClick()
})
I get a dataset is not defined error.
3) If I change it to this:
$('.layout-item-button').click(layoutItemButtonClick())
I get the same error.
4) For this:
$('.layout-item-button').click(layoutItemButtonClick)
I get an element is not defined error.
I know that if I call the function inside a function, this would be the current element, and if inside the click parentheses like in 3) and 4), it would be the local scope this. So, how do I pass both the element and the this from the click into my function.
And why/how does using parenthesis make a difference when calling a function defined as a constant?
Thanks in advance.
And why/how does using parenthesis make a difference when calling a function defined as a constant?
layoutItemButtonClick is like any other variable access. It resolves to the value of the variable, which is a function object.
layoutItemButtonClick() otoh calls the function and resolves to its return value.
Therefore,
$('.layout-item-button').click(layoutItemButtonClick())
passes the return value of layoutItemButtonClick (which is undefined) to .click whereas
$('.layout-item-button').click(layoutItemButtonClick())
passes the function object itself to .click.
I get an element is not defined error.
And rightly so because element is not defined in the scope accessible to layoutItemButtonClick. It is only defined inside DOMContentLoaded event handler.
You'd have to pass element as argument to layoutItemButtonClick. So the function should be declared as
export const layoutItemButtonClick = function(element) { ... }
Now we need to call layoutItemButtonClick such that this refers to the clicked element and we pass element as argument. We can do this using .call:
$('.layout-item-button').click(function() {
layoutItemButtonClick.call(this, element);
});
However, there is no need for using this inside layoutItemButtonClick. We can just make the element that triggered the event an explicit argument:
export const layoutItemButtonClick = function(trigger, element) {
const selectedLayout = trigger.dataset.layout.split("")
doQqthing(element);
};
and call it as
$('.layout-item-button').click(function() {
layoutItemButtonClick(this, element);
});
Related
I have this simple onclick eventfunction and i would like to know if it's possible to acces the variable that is inside it and use it outside this function, if not is there a way to do something similar?
document.querySelector('.check-parent').addEventListener('click', function() {
var a = 'abc';
return a;
});
console.log(a);
P.S.
In my homepage code i have 3 forms, each form has one id and it needs to display errors in case the fields are not completed properly. And when i click submit i get the parent id and that id goes in a switch function and determins with form it was and what errors needs to display
You'll have to get a few things correct:
The this variable changes inside the callback since the scope changes.
Hence bind outer this to your clickhandler(bind(this) in below snippet)
console.log(a) would not print undefined since it's again in different scope.
You'll have to trigger this call only after a click event is performed. Hence wrap it in a function & call this from the handler by passing the value.(this.fromClick(innerVariable) in below snippet)
Below's a sample snippet(ES5 demo & ES6 demo):
this.count =0;
document.getElementById('myButton').addEventListener('click', function() {
//Access outer variables
this.count++;
document.getElementById('buttonCount').innerHTML = this.count;
//Send something outside
var innerVariable = 'String from click handler!!';
this.fromClick(innerVariable);
}.bind(this));
this.fromClick = function (innerVariable) {
alert(innerVariable);
}
I have a global function defined in one place:
function addToCart (){
var prodText = $(this).parent().siblings(".item1").text();
$("#"+prodId+"shopC").children(".item1").text(prodText);
alert(prodText);
}
Then, I want to call it inside a HTML element with an inline onClick event:
onClick='addToCart()'
It is not working, but it works if I put the function code directly inside the onClick event, so that must be a this scope issue.
There are many questions/explanations about this scope but I must confess I miss a simple straight answer for this specific case (I tried to use "use strict" with success either).
How to make this work?
As per current implementation this doesn't refers to the element which invoked the function. It refers to window object.
You need to pass the current element context i.e. this to the function as
onClick='addToCart(this)'
and modify the function to accept element as parameter.
function addToCart (elem){
var prodText = $(elem).parent().siblings(".item1").text();
$("#"+prodId+"shopC").children(".item1").text(prodText);
alert(prodText);
}
Basically this inside a plain function will point to window. you have to pass the this context to the inline handler onClick='addToCart(this)'. Receive it and use it inside of event handler like below.
function addToCart (_this){
var prodText = $(_this).parent().siblings(".item1").text();
you have to pass this keyword where you inline calling the addToCart function then you can capture that element
onClick='addToCart(this)'
this object in your function does not point to the object where you added the onClick function to. It rather points to the window object.
You need to pass this as a param to your function.
function addToCart (trigger) { // Code goes here }
and call addToCart(this) in your onClick.
Learn more about this in javascript here.
I'm not sure if this has been asked before because I don't know what it's called.
But why wouldn't a method like this work? Below is just a general example
<script>
document.getElementById('main_div').onclick=clickie(argument1,argument2);
function clickie(parameter1,parameter2){
//code here
}
</script>
The code above would work fine if the event handler was assigned without parameters, but with parameters, it doesn't work. I think I read online that to overcome this problem, you could use closures. I'm assuming it's because of the parentheses ( ) that is calling the function immediately instead of assigning it to the event?
Because you're calling the function immediately and returning the result, not referencing it.
When adding the parenthesis you call the function and pass the result back to onclick
document.getElementById('main_div').onclick = clickie(); // returns undefined
so it's actually equal to writing
document.getElementById('main_div').onclick = undefined;
which is not what you want, you want
document.getElementById('main_div').onclick = clickie;
but then you can't pass arguments, so to do that you could use an anonymous function as well
document.getElementById('main_div').onclick = function() {
clickie(argument1,argument2);
}
or use bind
document.getElementById('main_div').onclick = yourFunc.bind(this, [argument1, argument2]);
It is however generally better to use addEventListener to attach event listeners, but the same principle applies, it's either (without arguments)
document.getElementById('main_div').addEventListener('click', clickie, false);
or bind or the anonymous function to pass arguments etc.
document.getElementById('main_div').addEventListener('click', function() {
clickie(argument1,argument2);
}, false);
The easiest way is:
yourElement.onclick = yourFunc.bind(this, [arg1, arg2]);
function yourFunc (args, event) {
// here you can work with you array of the arguments 'args'
}
When you say onClick = function() {...} you are registering your function with some internal JavaScript library. So when the "click" happens, that library invokes your function.
Now imagine you're the author of that library and someone registered their function with it. How would you know how many parameters to pass to the function? How would you know know what kind of parameters to pass in?
clickie(argument1,argument2)
This means to invoke the function and return its return value.
clickie
This simply is a reference to the function (doesn't invoke/execute it)
To bind an event to a element, you need to use either the attachEvent or addEventListener method. For example.
/* Non IE*/
document.getElementById('main_div').addEventListener('click', function () {}, false);
/* IE */
document.getElementById('main_div').attachEvent('onclick', function () {});
A function name followed by parentheses is interpreted as a function call or the start of a function declaration. The a onclick property needs to be set to a function object. A function declaration is a statement, and is not itself a function. It doesn't return a reference to the function. Instead it has the side effect of creating a variable in the global scope that refers to a new function object.
function clickie(param) { return true; }
creates a global variable named clickie that refers to a function object. One could then assign that object as an event handler like so: element.onclick = clickie;. An anonymous function declaration (often confused with a closure; for the difference see Closure vs Anonymous function (difference?)) does return a function object and can be assigned to a property as an event handler, as follows:
element.onclick = function(event) { return true; };
But this doesn't work:
element.onclick = function clickie(event) { return true;};
Why? Because function clickie(event) { return true;} is a statement, not a function. It doesn't return anything. So there is nothing to be assigned to the onclick property. Hope this helps.
Is there a way to cache a global variable for a function within a group of functions, without calling that function directly from another?
For example, if I have a group of functions wrapped in a parent function like this:
function parentFunction() {
var myVariable;
someDiv.addEventListener('click', function (e) {
myVariable = e.target;
});
anotherDiv.addEventListener('click', function (e) {
// use myVariable without it changing when the above is fired again.
});
}
The global variable is declared at the start, it is given a value in the first function, which carries over to the second for use.
But how can I stop it from continually updating in the second function, if the first function fires again?
Could I add another event-listener inside the second function to check if the first fires again and ensure the variable doesn't change?
You can set the variable only once in the first function:
someDiv.addEventListener('click', function (e) {
if (!clickedLink) {
clickedLink = e.target;
}
});
Or, you can apply any logic you want there. Sometimes, saving state like this in a semi-global for later use in a different event handler is a warning sign that you might have a design issue. If you explain more about what you're really trying to do, we could offer an opinion on whether there's a better way to solve your design issue.
Not sure if I fully understand the question. If you want to have two distinct bindings, you need two variables. Maybe so:
function parentFunction() {
var myVariable, anotherVariable;
someDiv.addEventListener('click', function (e) {
myVariable = e.target;
if (!anotherVariable) {
anotherVariable = e.target;
}
});
anotherDiv.addEventListener('click', function (e) {
// use anotherVariable
});
}
window.onload = function() {
document.getElementById('clickMe').onclick = runTheExample;
}
function runTheExample() {
alert('running the example');
}
This is a simple event handler for the onclick event for an html input button with id = clickMe.
In line 2, why is the call to function runTheExample not immediately followed by ()? I thought that to call a function you must pass it any variables/objects it expects in an open/close parenthesis, and if the function isn't expecting anything, you must still include the open and close parenthesis like runTheExample().
document.getElementById('clickMe').onclick = runTheExample;
The intention here is not to call runTheExample() but to assign the reference to the function runTheExample to the onclick event.
Internally, when the onclick event is fired, Javascript is able to call the function runTheExample through the reference you provided on the code above.
Snippet
var myFunction = function() { return 42; };
// Assigning the reference
myObject.callback = myFunction;
myObject.callback(); // Has the same effect as calling myFunction();
// Assigning by calling the function
myObject.callback = myFunction();
myObject.callback; // Returns 42
myObject.callback(); // Exception! Cannot call "42();"
That's not Javascript-specific. Passing functions by reference is available in many languages.
You use the parenthesis only to invoke (call) a function. When you're assigning it to onclick, you're merely passing it by reference.
To better understand this, think about the other method of declaring a function:
var runTheExample = function () {
alert('running the example');
}
Regardless of what method you use, runTheExample will contain a reference to the function (there are some differences, like the function reference not being available before assignment, but that's a different story).
Functions are objects in javascript. That line sets the onclick property of the click me element to the runTheExample function, it doesn't call that function right then.
var a =runTheExample; //sets a to runTheExample
a(); //runs the runTheExample function
So when the function name is referenced without the () it is referring to the function object, when you add the () it is a call to the function, and the function executes.
It's not calling it, but rather setting the property onclick. When a call is made to onclick(), it will then run the function you've defined. Note however that the context of this will be the object that calls it (document.getElementById('clickMe')).
You're not calling the function here. You're setting the function as an event handler, and the function is not actually called called until the event is fired. What you've written references the function; that's a different notion than actually calling it.
In this case, the runTheExample function is being treated as a variable and being assigned to the onclick event handler. You use () after a function name to call a function. If you added them here, what would happen is that runTheExample() would be called once during load, showing an alert, and then a null value would be assigned to the onclick handler.
Because it binds runTheExample to onclick event.
When you add () it triggers the function.