I started learn JavaScript and in some tutorials I saw that was used document.getElementById() and in some tutorials in same case was used "this" that was passed from control that fired the event.
Maybe someone can explain why should I prefer one way over an other?
Thank's a lot
Are you referring to the documentation from this MDN page on addEventListener? Make sure you look at the section on the value of this within the handler. The earlier examples use document.getElementById to look up an arbitrary element. For example, you could attach a click handler to a button (or any other element), that modifies some other element when it is clicked. In this case, you don't really do anything with the object that generated the click event. So in the handler, you will use document.getElementById to modify the element you want.
However, in some other cases you would like to modify the element itself. For example, you might want to change the color of an element the user clicks on, to let them know that its state has changed (a toggle basically). In this case, you want access to the element that actually generated the event, and you can do that by using this. Here this means "I am the HTML element who generated this event".
In a more general context, this can have different meanings, and it depends on the use case. In the context of event handlers, this means the element that generated the event. In other cases, such as in object-oriented JavaScript, this in a function can refer to the parent object of that function. JavaScript is flexible enough that a function can have whatever this value the author decides. In well-written code, this has a meaning that generally makes sense, and usually refers to some sort of "owning" context or object.
Functions assigned as Events have their this context as the Object to which the Event belongs. In other words, the Element itself.
// you can get Element a number of ways including document.getElementById('idHere')
function someFunc(){
this.style.color = 'blue';
}
Element.onclick = someFunc;
or
Element.addEventListener('click', someFunc);
or
Element.onclick = function(){
this.style.color = 'blue';
}
or
function someFunc(context){
context.style.color = 'blue';
}
Element.onclick = function(){
someFunc(this);
// more code here
// could use document.getElementById('whatever') to get HTML Element with id='whatever'
}
Related
Could someone please explain the concept of how the 'onlick' property of an element is working, pertaining to its syntax when it is assigned to a function, and its implementation where it is inherited from.
const FOO = document.querySelector('.bar');
FOO.onclick = function (e) {
e.preventDefault();
console.log('button clicked');
}
One area of confusion is regarding how does the browser know (in the implementation) to treat the onclick property as a click event.
How does assigning the onclick property of an element to a function result in the element being able to listen for click events - as opposed to say assigning a function to any other made up property of that element (whats happening behind the scenes?).
Is every element designed to always listen for click events and by assigning specifically the onclick property to a function it executes that function with the click event?
I am a beginner to programming, JavaScript, and object oriented concepts. I was hoping if someone could offer their insight and explain these concepts in any way.
Many thanks for your time and help
Yes, every element is designed to always listen for click events. By writing Element.onclick = function(){}, you are assigning a function to the Object (Element)'s onclick property, which will be executed when the element is clicked on. Essentially an Element is an Object, and its properties can be set just like any other Object.
An Object consists of property and value pairs. Consider the following object.
var obj = {color: "red"};
This Object has only one property, color, which has the value "red". If you were to assign another property to the Object, you could do this:
obj.background = "green";//or obj["background"] = "green";
You can assign a function as the value of one of an object's properties. An Element's onclick property is always run when it is clicked. When you update the value of it, it replaces the old value, and the new function you provide will be run when the Element is clicked on.
In JavaScript I'm attempting to set an onchange callback that accepts a parameter. However, how I'm currently doing it overrides the event object that is created. I don't actually need the event for my purposes, but I would like to know how I can capture both the event and any passed in parameters in case my needs change.
EDIT: For clarity, this onchange event could be called both programatically and by a user. There may be an instance where I'm creating an empty select element so the user can pick what they want, or creating a populated one based on some other interaction.
EDIT: Also, the below is a simplified example of a much larger code base. Assume that the scoping is not global of any of the variables. I'm really looking for an answer of how to specifically be able to capture both and event object (when called via user interaction) and another object (when called via code). It feels like having the atr parameter mean different things in different contexts is hacky - but I come more from a strongly typed background so it might be just me.
function update(atr) {
...
}
document.getElementById("myelement").onchange = update;
var atr = {"id":1,"param":"val1"};
// This gives me atr in the function as defined above
document.getElementById("myelement").onchange(atr);
// This way, however, gives me atr in the function as the event
document.getElementById("myelement").onchange();
What I would really like is something like this:
function update(e, atr) {
// Now I have e as the event and atr as the value I've passed in
}
document.getElementById("myelement").onchange = update;
var atr = {"id":1,"param":"val1"};
// This gives me atr in the function as defined above
document.getElementById("myelement").onchange(atr);
However the above code doesn't work. I suspect that I have to do something with bind() but as far as I can understand that I would simply be overriding the event's (this) object in the function like I'm doing now implicitly.
The accepted answer in this question Similar Question is basically what I want to do, but that is with React JS and I would like to do this without any frameworks. I've been trying to search for multiple parameters and onchange events and primarily getting React or unrelated responses. Either this is a harder question than I think, or I'm searching for the answer in completely the wrong way.
I will explain what happens in the linked answer as you mentioned that you want to achieve the same behaviour.
So:
<fieldset onChange={(e) => this.props.handleChange("tags", e)}>
This React code attaches anonymous function with one parameter e to the fieldset as onChange listener. This function in its body invokes another function, passing e with additional parameters.
Translating this into your code, you would like to achieve something like this:
function update(e, attr) {
// e is instance of Event
// attr is additional parameter
}
document.getElementById("myelement").onchange((e) => update(e, attr));
// or without ES6 arrow function:
document.getElementById("myelement").onchange(function(e){ update(e, attr); });
Also, be advised that proper way of attaching event listeners is by addEventListner API.
I'm not sure I understand exactly what you're trying to do, but first you need to distinguish between the case that the event is triggered by the user and the case that you call the event programatically, when you call it programatically there is no event.
you can do something like this:
You mentioned that you use select, the logic is that when a change in the select occurs the event is thrown and you get the selected value, in your case the value can be the content of the atr var:
HTML
<select id="myelement" onchange="update(event)">
<option value='{"id":1,"param":"val1"}'>val1
<option value='{"id":2,"param":"val2"}'>val2
</select>
JavaScript
function update(e) {
var atr = JSON.parse(document.getElementById("myelement").value);
//now you have access both to the event and the 'parameter'
}
This covers the case when the event is triggered by the user, when you want to trigger the event programatically, since there is no event, use a different function that take the atr parameter.
I am currently working through this tutorial: Getting Started with jQuery
For the two examples below:
$("#orderedlist").find("li").each(function (i) {
$(this).append(" BAM! " + i);
});
$("#reset").click(function () {
$("form").each(function () {
this.reset();
});
});
Notice in the first example, we use $(this) to append some text inside of each li element. In the second example we use this directly when resetting the form.
$(this) seems to be used a lot more often than this.
My guess is in the first example, $() is converting each li element into a jQuery object which understands the append() function whereas in the second example reset() can be called directly on the form.
Basically we need $() for special jQuery-only functions.
Is this correct?
Yes you only need $() when you're using jQuery. If you want jQuery's help to do DOM things just keep this in mind.
$(this)[0] === this
Basically every time you get a set of elements back jQuery turns it into a jQuery object. If you know you only have one result, it's going to be in the first element.
$("#myDiv")[0] === document.getElementById("myDiv");
And so on...
$() is the jQuery constructor function.
this is a reference to the DOM element of invocation.
So basically, in $(this), you are just passing the this in $() as a parameter so that you could call jQuery methods and functions.
Yes, you need $(this) for jQuery functions, but when you want to access basic javascript methods of the element that don't use jQuery, you can just use this.
When using jQuery, it is advised to use $(this) usually. But if you know (you should learn and know) the difference, sometimes it is more convenient and quicker to use just this. For instance:
$(".myCheckboxes").change(function(){
if(this.checked)
alert("checked");
});
is easier and purer than
$(".myCheckboxes").change(function(){
if($(this).is(":checked"))
alert("checked");
});
this is the element, $(this) is the jQuery object constructed with that element
$(".class").each(function(){
//the iterations current html element
//the classic JavaScript API is exposed here (such as .innerHTML and .appendChild)
var HTMLElement = this;
//the current HTML element is passed to the jQuery constructor
//the jQuery API is exposed here (such as .html() and .append())
var jQueryObject = $(this);
});
A deeper look
thisMDN is contained in an execution context
The scope refers to the current Execution ContextECMA. In order to understand this, it is important to understand the way execution contexts operate in JavaScript.
execution contexts bind this
When control enters an execution context (code is being executed in that scope) the environment for variables are setup (Lexical and Variable Environments - essentially this sets up an area for variables to enter which were already accessible, and an area for local variables to be stored), and the binding of this occurs.
jQuery binds this
Execution contexts form a logical stack. The result is that contexts deeper in the stack have access to previous variables, but their bindings may have been altered. Every time jQuery calls a callback function, it alters the this binding by using applyMDN.
callback.apply( obj[ i ] )//where obj[i] is the current element
The result of calling apply is that inside of jQuery callback functions, this refers to the current element being used by the callback function.
For example, in .each, the callback function commonly used allows for .each(function(index,element){/*scope*/}). In that scope, this == element is true.
jQuery callbacks use the apply function to bind the function being called with the current element. This element comes from the jQuery object's element array. Each jQuery object constructed contains an array of elements which match the selectorjQuery API that was used to instantiate the jQuery object.
$(selector) calls the jQuery function (remember that $ is a reference to jQuery, code: window.jQuery = window.$ = jQuery;). Internally, the jQuery function instantiates a function object. So while it may not be immediately obvious, using $() internally uses new jQuery(). Part of the construction of this jQuery object is to find all matches of the selector. The constructor will also accept html strings and elements. When you pass this to the jQuery constructor, you are passing the current element for a jQuery object to be constructed with. The jQuery object then contains an array-like structure of the DOM elements matching the selector (or just the single element in the case of this).
Once the jQuery object is constructed, the jQuery API is now exposed. When a jQuery api function is called, it will internally iterate over this array-like structure. For each item in the array, it calls the callback function for the api, binding the callback's this to the current element. This call can be seen in the code snippet above where obj is the array-like structure, and i is the iterator used for the position in the array of the current element.
Yeah, by using $(this), you enabled jQuery functionality for the object. By just using this, it only has generic Javascript functionality.
this reference a javascript object and $(this) used to encapsulate with jQuery.
Example =>
// Getting Name and modify css property of dom object through jQuery
var name = $(this).attr('name');
$(this).css('background-color','white')
// Getting form object and its data and work on..
this = document.getElementsByName("new_photo")[0]
formData = new FormData(this)
// Calling blur method on find input field with help of both as below
$(this).find('input[type=text]')[0].blur()
//Above is equivalent to
this = $(this).find('input[type=text]')[0]
this.blur()
//Find value of a text field with id "index-number"
this = document.getElementById("index-number");
this.value
or
this = $('#index-number');
$(this).val(); // Equivalent to $('#index-number').val()
$(this).css('color','#000000')
I was looking at this basic example below (which makes all images in the DOM semi-transparent on mouseover), and was confused as to how an arbitrary function, such as handleMouseOver, receives an event object if you give it an argument.
How is it that the act of assigning such a function to the onmouseover attribute tells it to modify this function in this way, as there's nothing inherent in the function definition itself that says: "please pass me an event"? Is the assignment operator being overloaded somehow? Or is the browser doing some extra work here? I would really appreciate a link to a detailed explanation of this phenomenon because it doesn't seem to make any sense looking at it as pure JavaScript (to me at least!)
function handleMouseOver(e) {
e.target.style.opacity = 0.5;
}
function handleMouseOut(e) {
e.target.style.opacity = 1;
}
var elements = document.getElementsByTagName("img");
for (var i = 0; i < elements.length; i++) {
elements[i].onmouseover = handleMouseOver;
elements[i].onmouseout = handleMouseOut;
}
Lets break it down by taking one browser's example. IE'S OnMouseOver Event for instance.
In the remarks section it says it passes IHTMLEventObj for ALL events even for the events that don't require it such as Body.OnLoad.
When we go into IHTMLEventObj's detail, we read the following remarks
Although all event properties are available to all event objects, some properties might not have meaningful values during some events
So, Event object is passed regardless; you have to access the object in some specific events and get event-specific properties to get event-related data.
onmouseover, for example, is an event handler. When the event handler needs to be called (in this case when the browser javascript engine decides it) then it will call it be passing it some pre-determined arguments (all good documentation will explain what those arguments are). Your use of those arguments is optional however.
This can be demonstrated with a manual function call like so:
function myFunction(e){
alert(e.myProperty);
}
//assign the handler
var handler = myFunction;
//when required, create event parameter data and call the function assigned to the handler
var myE = { myProperty: "some data" };
handler(myE);
It is not "exactly" how it works (because I don't know how browsers have chosen to implement their code), but it shows the concept.
Here is an example in action
Not only the event object is passed, but also the this value within the function is set to the event target. This is done by the browser, and dictated by the DOM specification.
EDIT:
I was hoping to find something more detailed in the DOM specification (I'm sure I've seen that before), but so far I found this:
In JavaScript, user-defined functions are considered to implement the EventListener interface. Thus the Event object will be provided as the first parameter to the user-defined function when it is invoked. Additionally, JavaScript objects can also implement the EventListener interface when they define a handleEvent method.
https://dvcs.w3.org/hg/dom3events/raw-file/tip/html/DOM3-Events.html#glossary-event-handler
By the way, the last sentence is talking about an interesting way to bind event listeners, in an OO context.
You can pass whatever arguments you like to any JavaScript function.
Defining them in the function definition just means you have a named, local variable to access them with.
That is to say:
function foo() {
}
foo("hello");
… won't throw an error.
When a function is treated as an event handler (which is what code provided by the browser will do if you assign a function to the onmouseover property of a DOM node) then the event object will be passed as an argument.
I have an interesting problem, and I think I got to the root of it, but I wanted to be sure. I have a link that calls a function called remove(). All browsers except Chrome had no issues with the function. However, the link that is clicked disappeared in Chrome, even when I simplified the function as in the example below. I have seen this question: Can't use "download" as a function name in javascript. In the links, however, I did not see anything about "remove" as a reserved keyword. My question is this, I am correct about this being a keyword? If so, is there anywhere I can find a list of Google keywords? I have searched and have not found this to be a problem anywhere else.
Remove
Javascript:
function remove(){
alert("Hi");
}
Elements in Chrome have a .remove() method which allows for self-removal of an element instead of having to do it from the parent.
The trouble is that when using attribute handlers, you get a different scope chain. That scope chain includes the element itself, as well as the document. This means that all properties of the element and document show up as variables.
Because you named your function remove(), and because it's a global function/variable, it is being shadowed by the .remove property (now variable) on the element itself. This can be seen with an alert. If you change your handler to:
onclick="alert(remove)"
...you'll get something like:
function remove() { [native code] }
So it's not that it's reserved, but rather that it's used as a property which ends up shadowing the global.
To fix it, either use the global directly:
onclick="window.remove()"
Or change the function name.
I can't find any documentation on it, but DOM elements in Chrome have a native method remove that apparently removes them. In onclick, this actually refers to the element itself so it ends up calling this.remove() which removes the element. To get around this, you can just call window.remove() instead.
http://jsfiddle.net/3YkZH/1/
It would also be better to use standard event binding via addEventListener which does not have this problem when simply calling remove:
http://jsfiddle.net/3YkZH/2/
I had no issue in chromium using it, well not in this manner
Remove
function remove() {
alert("Hi");
}
document.getElementById("remove").addEventListener("click", remove, false);
on jsfiddle
Inline javascript is considered bad practice.
If you have more elements using the same function, just add more lines, like this
document.getElementById("remove1").addEventListener("click", remove, false);
document.getElementById("remove2").addEventListener("click", remove, false);
document.getElementById("remove3").addEventListener("click", remove, false);
document.getElementById("remove4").addEventListener("click", remove, false);
or you could get a nodelist and loop through that
var nodelist = document.querySelectorAll("[id^=remove]");
Array.prototype.forEach.call(nodelist, function (element) {
element.addEventListener("click", remove, false);
}
You can take a look at another answer here on SO to find out more about the differences between event binding methods, also do a little G searching on the subject will give you further information. And of course, you would have avoided the issue that you were experiencing by doing it in this manner.