Javascript function to just get all elements from getElementsByClassName - javascript

First things first, I've looked in a bunch of seemingly related questions that don't directly relate to my problem:
javascript getElementsByClassName from javascript variable
getElementsByClassName doesn't select all my Navigation elements
Javascript: getElementsByClassName not giving all elements
Javascript document.getElementsByClassName not returning all elements
How to change class for all elements retrieved by document.getElementsByClassName
getElementsByClassName vs. jquery
If there is another question that already addresses my specific problem I apologize and please direct me there.
I'm trying to extract opening and current line data from the following page: https://www.sportsbookreview.com/betting-odds/ncaa-basketball/ and it's only returning data for a certain subset of games. The code is below.
convertHalfLines = stringVal => {
let val
let halfLine = false
if (stringVal.substr(-1) === '\u00BD') {
val = parseFloat(stringVal.slice(0,-1))
halfLine = true
} else {
val = parseFloat(stringVal)
}
return halfLine ? val + (Math.sign(val) * 0.5) : val
}
let games = document.getElementsByClassName("_3A-gC")
let gameInfo = Object.keys(games).map(game => {
let teams = games[game].getElementsByClassName("_3O1Gx")
let currentLines = games[game].getElementsByClassName("_3h0tU")
console.log('currentLines',currentLines)
return {
'homeTeam': teams[1].innerText,
'awayTeam': teams[0].innerText,
'homeWagerPct': parseFloat(currentLines[1].innerText),
'awayWagerPct': parseFloat(currentLines[0].innerText),
'homeOpeningLine': convertHalfLines(currentLines[3].getElementsByClassName('_3Nv_7')[0].innerText),
'awayOpeningLine': convertHalfLines(currentLines[2].getElementsByClassName('_3Nv_7')[0].innerText),
'homeCurrentLine': convertHalfLines(currentLines[5].getElementsByClassName('_3Nv_7')[0].innerText),
'awayCurrentLine': convertHalfLines(currentLines[4].getElementsByClassName('_3Nv_7')[0].innerText),
}
})
The code returns data for a certain set of games, which in and of itself is not consistent. Sometimes it returns data for the first six games, sometimes for the first eight, sometimes less or more than these. Is there something I just don't know about JS that I'm missing or is something else going on?

Related

getElementsByClassName not showing data in an element [duplicate]

This question already has answers here:
What do querySelectorAll and getElementsBy* methods return?
(12 answers)
Closed last year.
I know there are a lot of questions regarding the getElementsByClassName not working, however I browsed through many and coudldnt find an answer for my situation.
Basically I have the following code:
<script>
var res = localStorage.getItem('img');
if(res == null){
const myList = ['🐒', '🐕', '🐈', '🐅', '🐎', '🦓', '🐄', '🦒', '🐘', '🦔', '🦉', '🐊', '🦖', '🐬', '🦈', '🦋', '🐞', '🦂'];
res = myList[Math.floor(Math.random() * myList.length)];
localStorage.setItem('img', res);
}
console.log(res);
document.getElementsByClassName("emoji").innerHTML = res
And several spans with same class:
<span class="emoji" style="font-size: 40px !important;"></span>
The problem is that the "res" doesn't print anything in span.
The console log prints everything fine and LS stores the information perfectly .
I have tried with ID's:
document.getElementsById("emoji").innerHTML = res
And it works perfectly, however only with the first div (as it should i suppose).
What could I be doing wrong in this situation?
Maybe I am not able to see a very simple mistake in my code.
If you specify classname so you have to give index to the class as it puts response only in the first element in the case of id, it is unique but in case of class you have to specify.
document.getElementsByClassName("emoji")[0].innerHTML = res;
Multiple elements can have the same class name. getElementsByClassName returns an array of elements that have the class name (it's Elements not Element). So if you have only 1 element with that class name, you can do document.getElementsByClassName("emoji")[0].innerHTML = res.
getElementByClassName always return array of element, usually can read an element from array as index basis, also similar way can get the element from getElementByClassName.Pls see the below snippet.
const myList = ['🐒', '🐕', '🐈', '🐅', '🐎', '🦓', '🐄', '🦒', '🐘', '🦔', '🦉', '🐊', '🦖', '🐬', '🦈', '🦋', '🐞', '🦂'];
var res = myList[Math.floor(Math.random() * myList.length)];
document.getElementsByClassName("emoji")[0].innerHTML = res
<span class="emoji" style="font-size: 40px !important;"></span>

Checking if two values per key are true in an associative object

I have an object, written as follows:
var color = "darkred";
var source = "person1"; //this is generated elsewhere and changes
var target = "work23"; //this is generated elsewhere and changes
link = {
color: color,
source: source,
target: target,
value:1
}
This object gets added to an array, links, as follows via a function that is meant to check first to see if it already exists in the array:
var links = [];
function person_linker(link) {
for (var key in links) {
if (links[key].source === link.source && links[key].target === link.target) {
}
else
{
links.push(link);
}
}
}
The problem I'm running into is that it doesn't seem to actually do this check and just adds the link object for however many keys are in links. Everything I've read indicates that writing the if statement is how such a check is made, but most of that information assumes you're only going after one value per key. It's obvious that && is not the way to go, but I've tried separating the two out, doing find, indexOf, and filter statements, and nothing seems to work. The code as is technically returns what I want but because it allows multiple link objects to be added to links it eats up memory when it does the check and creates spurious entries -- with the potential of tens of thousands of extra lines added to the object. What am I doing wrong, here? I'm sure it's a simple fix, but I cannot for the life of me figure out what Javascript wants.
You need to use array filter methods. Here is the example where I use once to check if there is already added link. Also it will be more efficient, because it will skip all of the unnecessary checks after the presented link found in links array.
See more here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/some
let color = "darkred";
let source = "person1"; //this is generated elsewhere and changes
let target = "work23"; //this is generated elsewhere and changes
let link = {
color: color,
source: source,
target: target,
value: 1,
};
const links = [];
function person_linker(link) {
const linkAlreadyAdded = links.some(presentedLink => {
return (presentedLink.source === link.source) &&
(presentedLink.target === link.target)
});
if (linkAlreadyAdded) {
console.log('Check failed.');
} else {
console.log('Check passed.');
links.push(link);
}
}
console.log(links);
person_linker(link);
console.log(links);
person_linker(link);
console.log(links);

Completing an item adds two new lines to it, without such a thing in the function it self

I have recreated a todo list on my own, after I've watched a tutorial, and everything works fine, 99% of it at least. Theres only one tiny problem, nothing deal breaking, but it bothers me a lot because I can't find the origin of the issue in the function, even though I've narrowed it down using the debugger. The problem itself is that, whenever I mark an item as "completed" in my todo list, it adds two new empty lines to it (like if someone literally clicked Enter x2, that's how its showcased in the console log). And the issue happens "per item", so its not like if I mark one as completed, it adds two new lines to each item, but just to the one being marked / unmarked. Here's a chunk of the code with the function that I supposedly narrowed it down to:
function completeItem(){
const item = this.parentNode.parentNode;
const parent = item.parentNode;
const id = parent.id;
const value = item.innerText;
if(id === "todo"){
data.todo.splice(data.todo.indexOf(value), 1)
data.completed.push(value);
// Notification.
notification.innerHTML = "<p>Task completed.</p>";
notification.classList.add("notification");
notification.classList.add("notificationCompleted");
setTimeout(() => {
notification.classList.remove("notification");
notification.classList.remove("notificationCompleted");
notification.innerHTML = "";
}, 2000);
} else {
data.completed.splice(data.completed.indexOf(value), 1);
data.todo.push(value);
}
dataObjectUpdate();
console.log(data);
const target = (id === "todo") ? document.getElementById("completed"):document.getElementById("todo");
parent.removeChild(item);
target.insertBefore(item, target.childNodes[0]);
}
Also here's the link to the whole script file on hastebin, if needed:
https://hastebin.com/kuwomiqazu.cs .
Here's a link to a codepen showcasing the issue:
https://codepen.io/pecko95/pen/XBpoGr
Thanks in advance.
textContent returns the text content of all elements, while innerText
returns the content of all elements, except for <script> and <style>
elements.
If you use textContent bug will be fixed.
Replace
const value = item.innerText;
with
const value = item.textContent;

search within an array in javascript

I've been trying for a while now to search within an array, I've looked at all the other questions that even somewhat resemble mine and nothing works, so I'm asking for any help you can give now..
I have an array with a more complex insides than a simple string array
var elementDefns = [
{"element":"water", "combos": {"air":"steam", "earth":"sand"} },
{"element":"fire", "combos": {"earth":"lava", "air":"energy"} },
{"element":"air", "combos": {"water":"steam", "earth":"dust"} },
{"element":"earth", "combos": {"water":"swamp", "fire":"lava"} },
];
Two elements are picked (by the users) which are combined to create new elements. I'd like to search through the elements for any combos that can be made. Ideally, I'd want to use Array.prototype.find, although I can't figure out how to use polyfills correctly and i'm unsure if i'm writing it correctly, so it continues to not work
var elementOne = $("#board img:first-child").attr('id');
var elementTwo = $("#board img:last-child").attr('id');
function findElement(element) {
return elementDefns.element === elementOne;
}
board is the id div where the element cards go to once clicked. I also tried a loop
for (var i=0, tot=elementDefns.length; i < tot; i++) {
var indexHelp = elementDefns[i].element;
var find = indexHelp.search(elementOne);
console.log(find);
}
I'm trying to post a question that's not too long, but I'm sure there's lots more about my code i need to adjust in order to do this. I guess I'm just asking if there's something obvious you think i could work on. I've looked at most of the answers on this site to similar problems but its all just going horribly wrong so any other support would be greatly appreciated..
I have an array with a more complex insides than a simple string array
Yes, but why? Get rid of the extra layers and this is trivial
var e1 = "water";
var e2 = "air";
var elementDefns = {
"water": {"combos": {"air":"steam", "earth":"sand"} },
"fire": {"combos": {"earth":"lava", "air":"energy"} },
"air": {"combos": {"water":"steam", "earth":"dust"} },
"earth": {"combos": {"water":"swamp", "fire":"lava"} },
};
elementDefns[e1].combos[e2] = > "steam"
If you want to keep your data-structure, you can filter through it like this:
var matches = elementDefns
.filter(e => e.element == first && e.combos[second] !== null)
.map(e => e.combos[second]);
The first row filters out all matches, and the secon maps it over to the actual match-string (element name). The find() you speak of just returns the first value that matches, and i guess you want all, so that would be the filter() method.

slice different arrays and return selected values

I am working on a problem. I do not know the right question to ask in order to solve this problem. I have gotten what seems to be the required results but the verification problem for the solution does not work. I am not sure if I am solving it correctly. Basically I am given an array and I have to filter out elements from that array by slicing certain ingredients.
question: "We only use the elements that the instruction tells us to. So, we need to create a slice of the given array of elements (taken from the beginning) to resemble only the elements we are using. If the instruction doesn't say anything, we only take the first element."
var hammerIngredients = ['iron', 'granite', 'copper'];
var spearIngredients = ['iron', 'granite', 'copper'];
var panIngredients = ['iron', 'granite', 'copper'];
take(hammerIngredients); // returns ['iron']
take(spearIngredients, 2); // returns ['iron', 'granite']
take(panIngredients, 3); // return ['iron', 'granite', 'copper']
"If the instruction says to use more than the elements listed, we use all the elements in the array. If the instruction says to use no elements, we return an empty array."
var plateIngredients = ['iron', 'granite', 'copper'];
take(plateIngredients, 0); // returns []
So I have tried to do the program and I have done the following. It appears to work, but when I try to verify it I get that it is invalid.
function take(ingredients, slicer) {
if (arguments.length === 1) {
slicer = 1;
}
if (ingredients === hammerIngredients){
return ingredients.slice(0, slicer);
} else if(ingredients === spearIngredients) {
return ingredients.slice(0,slicer);
} else if (ingredients === panIngredients) {
return ingredients.slice(0,slicer);
} else if (ingredients === plateIngredients) {
return ingredients.slice(0,slicer)
} else {
return;
}
}
And I have no idea why. Help please!
you have no logic for if the slicer parameter is 0, in which case you need to return an empty array.
Put this line in there and it should work, based on the requirements you gave:
if (slicer === 0) {
return [];
}
You code currently only works if one of those three exact arrays are used. Does the verification code create and use only those arrays?
Your code does not need to be tied to existing ingredient arrays. After setting the default slicer value you can just:
return ingredients.slice(0,slicer);

Categories

Resources