Element access on result of getElementsByClassName/querySelectorAll - javascript

I'm trying to access to my elements by getElementsByClassName/querySelectorAll function, but I don't understand what happens when I try to get element from the result.
var cells = document.getElementsByClassName('mapAtt');
console.log(cells); // [item: function]
console.log(cells[0]); // undefined
console.log(cells.item(0)); // none
console.log(cells.length); // 0
var cells2 = document.querySelectorAll(".mapAtt");
console.log(cells2); // [item: function]
console.log(cells2[0]); // undefined
console.log(cells2.item(0)); // none
console.log(cells2.length); // 0
I read that return of this two functions isn't an array but a nodeList, but even with the item function, it doesn't work.
cells1 and cells2 show me the right thing, a list with my 22 elements, but I cannot access them with array/nodeList methods.
Elements were created with d3.js, but if I don't say mistakes, it is supposed to create well-boned HTML DOM element. So why doesn't it work?

Related

Calling a custom method on the Array prototype in Nodejs

I'm trying to add a custom method on the prototype of the Array object:
Array.prototype.demo = function(){
this.forEach(i=>console.log(i))
}
But, I'm receiving the error below when I'm calling the method like this:
[1,2,3].demo()
// Error: TypeError: Cannot read property 'demo' of undefined
However, it runs successfully when I change it to:
const arr = [1,2,3];
arr.demo()
// Output: 1, 2, 3
PS. This is in nodejs
To reproduce the error in the browser, copy/paste the full block at once and click enter.
UPDATE: It sounds like we need to add a semicolon to make it work:
Array.prototype.demo = function(){
this.forEach(i=>console.log(i))
}; <=== added semicolon here to work #jfriend00
[1,2,3].demo();
However, now this next code works WITHOUT semicolon!!
String.prototype.demo = function(){
this.split('').forEach(c=>console.log(c))
}
'hello'.demo();
Quick Fix - Add Semi-colon
Add a semi-colon at the end of your function definition:
Array.prototype.demo = function(){
this.forEach(i=>console.log(i))
}; // <======
[1,2,3].demo();
And, it will work.
What's Happening?
The problem is that the [1,2,3] is being combined with the previous function (whitespace between them collapsed). In that circumstance, the [1,2,3] becomes just [3] and tries to read the [3] property from the function object. If you put the semi-colon at the end of the function definition, then that signals the end of the function definition statement and the [1,2,3] can then be interpreted as a static array definition.
It's all about context. In some circumstances in Javascript, [x] is a property access. In other circumstances, it's a static array definition. Without the semi-colon, it was getting interpreted as the property access instead of the array definition.
Remember that functions are objects in Javascript so they can have properties and can respond to [x] as a property access on them.
So, without the semi-colon at the end of the function you essentially have this:
Array.prototype.demo = function() {...}[3].demo();
Because the whitespace is collapsed between the end of your function and the [1,2,3]. That means the JS interpreter is expecting the [] to be a property name so it evaluates the statement inside the [] and in that context [1,2,3] turns into [3] (the 1,2,3 is evaluated which takes the value of the last comma separated statement which is 3).
More Detailed Explanation
Think of it like this:
// defines function
let f = function() {};
// attempts to read a property from that function object
let o = f [1,2,3]; // this is the same as let o = f[3]
// tries to call `.demo()` on the value read from that property
// which was undefined so this throws
o.demo();
Functions Are Objects
As a demonstration of how functions are objects, see this example that actually works!
// defines function
let f = function() {};
f[3] = {demo: function() { console.log("demo!!!");}}
// attempts to read a property from that function object
let o = f[1,2,3]; // this is the same as let o = f[3]
// tries to call `.demo()` on the value read from that property
// which was undefined so this throws
o.demo();
Here, we actually put a property on the [3] property of the function so when f[1,2,3] reads that property, it actually gets an object with a .demo() method on it so when we then call it, it all works. I'm not suggesting one would ever code this way, but I am trying to illustrate how f[1,2,3] is just reading the [3] property from the function object.
Good Reason Not to Leave out the Semi-colons
These odd cases are a good reason not to leave out semi-colons, even though you usually (but not always) get away with it.
The reason is that functions are objects, so if we don't add a semicolon, JavaScript will try to access a property on the function object, after it evaluates the comma operator like this:
function() { ... }[1,2,3].demo();
function() { ... }[3].demo();
undefined.demo();

Setting Variable Assignments with property display

I'm still a novice when it comes to JavaScript and was trying to make my code more cleaner and was wondering why the top scenario works but the bottom doesn't? Am I missing something?
var partner = document.getElementById('partner');
var providedBy = document.getElementById('providedBy');
partner.style.display = "none";
providedBy.style.display = "none";
But this does not?
var partner = document.getElementById('partner');
var providedBy = document.getElementById('providedBy');
collection = partner + providedBy;
collection.style.display = "none";
In the console it gives me error saying Cannot set Property 'display' of undefined. Am I supposed to define it somewhere first? I console logged the new variable and it returned both div elements.
collection is of type string as the + operator automatically call for both their toString() function.
Now what you are trying is to access a property of collection.style which does not exist because you are operating on a string. That's the reason for the error message you are getting.
You could do something like:
var collection = [];
collection.push(document.getElementById('partner'));
collection.push(document.getElementById('providedBy'));
collection.forEach(function(element) {
element.style.display = 'none';
}
which would be something I think you are trying to archive.
just to complement the accepted answer, I think you should understand why you get this error.
For what i understand from your code, you are trying to set the css of both variables partner and providedBy to display : none.
Your first piece of code works because you do this separately, while in your second code you try to add with the (+) operator both nodes, which evaluates to the string "[object HTMLDivElement][object HTMLInputElement]".
Then you try to call .style on that string which evaluates to undefined, and then you try to call display on that undefined value, this is where you get the error.
You could leave your code just like that since there are not too many variables, but if you wanted to do something that worked on multiple variables you could
create an array
push your objects into the array
create a function that loops over the elements of the array and set their style.display = "none" to individually.
In JavaScript you have to declare all of your variables. Secondly, you can't point to two objects at once by using the + operator. JavaScript interprets this as trying to concatenate the two objects, which it can't do in this way. It will return the string [object Object][object Object]
In order to affect two Objects at the same time you would need to create a function or use an existing method.

JavaScript error: Uncaught TypeError: Cannot read property 'remove' of undefined

I have a script to remove uploaded files after Add to success, but I get this error on site when it loads.
"Uncaught TypeError: Cannot read property 'remove' of undefined"
What's missing?
<script>
onload=function() {
document.querySelectorAll("li[id^='uploadNameSpan']")[0].remove();
}
</script>
Basically, your issue is that, at the time you call this code, you don't have any elements in the DOM corresponding to the query "li[id^='uploadNameSpan']". So querySelectorAll returns an empty NodeList which has undefined at the 0 position (or any position for that matter).
Breakdown of what is happening:
var liElements = document.querySelectorAll("li[id^='uploadNameSpan']"); // this returns an empty NodeList
var nonExistentFirstElement = liElements[0]; // this is undefined, there's nothing at the first position
nonExistentFirstElement.remove(); // thus, this is an error since you're calling `undefined.remove()`
Depending on your use case, one thing you can do is have a check for the amount of items returned before trying to remove:
var liElements = document.querySelectorAll("li[id^='uploadNameSpan']");
if (liElements.length > 0) {
liElements[0].remove();
}
In general, you have to make sure to have the element in the DOM at the time you are trying to remove it.

Javascript: Delete operator

I am looking at the Mozilla Developers website on the concept of the delete operator. In the last sub section of the page referring to “Deleting array elements” two similar scripts are shown, but the only difference in the scripts is how they modified the array.
In the first script, I quite don’t understand why “if” statement does not run. My current understanding is that delete operator “removes the element of the array”. If I were to type trees[3] in the console, it would return undefined in the console.
var trees = ["redwood","bay","cedar","oak","maple"];
delete trees[3];
if (3 in trees) {
// this does not get executed
}
The second script seems to "mimic" the delete, but not literally. Undefined is assigned to trees[3]. It doesn’t make sense to me how the “if” block runs in this script, but the first example does not. Can anyone help me understand this JavaScript behavior?
var trees = ["redwood","bay","cedar","oak","maple"];
trees[3] = undefined;
if (3 in trees) {
// this gets executed
}
There is a huge difference between the two methods you are trying:
Method 1:
You are deleting, destroying, completely removing the key 3 in your array called tree, hence there is no 3 in tree left, and the if check returns false.
Method 2:
You are assigning a new value to the key 3, which is undefined, there is still 3 in tree, and the if check returns true.
In your second example the key 3 still exists. It just holds a value that happens to be undefined. It IS confusing, but that's just the way Javascript is.
The in operator just checks if the key exists, not if the value is defined.
If you were to output the whole arrays after each of your "deletions" the first example would display something like this:
["redwood", "bay", "cedar", 4: "maple"]
Whilst the second example would print out something like this:
["redwood", "bay", "cedar", undefined, "maple"]
So as you can see, in your first example the key is completely missing and it continues with the next key which is 4. In the second example the key still exists, but it's value is set to undefined.
There is a difference between undefined which is set by the user and undefined which the javascript engine returns once something is actually undefined, meaning doesn't exist.
javascript can tell the difference between the two.
So in your example, when you do this:
var trees = ["redwood","bay","cedar","oak","maple"];
trees[3] = undefined;
if (3 in trees) {
console.log("hi");
}
javascript can tell that property 3 exists, but it was set to undefined by the user.
to prove so you have the following:
if (5 in trees) {
console.log("hi");
}
the property 5 of the array was never created, javascript knows it's undefined
by lack of creation and regards it as a property which doesn't exist, and therefore doesn't display the "hi"
if(3 in tree) {
//Stuff that won't get executed
}
is in fact correct, the thing is that in operator in Javascript does not work like in python, it simply checks if an object has a proprety. An array in javascript has a proprety 0, just like a string has a proprety 2 with the value someString[2].
the difference between delete object[prop]; and object[prop] = undefined; can be seen through object.hasOwnProperty(prop); or iterating through values or props of the object.

Are jQuery created nodes fakes?

I have been fighting with this for hours, and yet it evades my comprehension...
var newLabel = $('<div></div>');
newLabel.appendTo("#f0");
console.log($("#f0").html()); // <br><div></div>
console.log(newLabel); // [object Object]
var div = newLabel.first().get();
console.log(div); // [object HTMLDivElement]
if( div instanceof HTMLDivElement ) { console.log("VALID"); } //
else { console.log("INVALID"); } // INVALID
console.log(div.appendChild); // undefined
We create a div element using jQuery and append it to a DOM element. It goes in, check. Object prints as "HTMLDivElement", check.
HOWEVER. It fails the instanceof. Also, it should have the method appendChild, but its undefined. (Indeed, it throws an error if I try to call it.)
What on earth is happening here? Is the element jQuery created for us, a fake?
get() returns an array, so div is an array in your case (which obviously is not an HTMLDivElement nor does it have a method appendChild). See: http://api.jquery.com/get/#get2. If you use .get(0) (or just [0]) instead, you'll get the actual div element.

Categories