element.getElementsByClassName is not a function - javascript

Currently I'm working in card filter, but I get jobCards[card].getElementsByClassName is not a function.
const cardHasRequirementFilter = function(card){
for(let requirementInFilter in listForFiltering){
let requirementsByCard = jobCards[card].getElementsByClassName("job-requirements__requirement");
for(let requirementInCard in requirementsByCard){
if(requirementInCard.innerHTML === requirementInFilter.innerHTML ){
return true;
}
}
}
return false;
}
When I call that function i do it this way
jobCards[card].style.display = cardHasRequirementFilter(card)===true?"flex":"none";
I tried with:
jobCards[card].style.display = cardHasRequirementFilter(jobCards[card])===true?"flex":"none";
const cardHasRequirementFilter = function(card){
for(let requirementInFilter in listForFiltering){
let requirementsByCard = card.getElementsByClassName("job-requirements__requirement");
for(let requirementInCard in requirementsByCard){
if(requirementInCard.innerHTML === requirementInFilter.innerHTML ){
return true;
}
}
}
return false;
}
And i get the same error...
I tried on Edge and chrome.
All my code is:
const btnsRequirements = document.getElementsByClassName("job-requirements__requirement");
const jobCards = document.getElementsByClassName("job-list__card-job");
/* All non repetible requirements existent. */
const listRequirements = {};
/* The cards will be filtered by this requirements to be
filtered, if it's empty, then all cards will be shown. */
const listForFiltering = {};
for (let requirement of btnsRequirements) {
let text = requirement.innerHTML;
listRequirements[text] = text;/* Creates a new property with the same value, if already existe, it's overited. */
requirement.addEventListener("click", function () {
let requirementClicked = this.innerHTML;
listForFiltering[requirementClicked] = requirementClicked;
filterCardsByRequirementsChoosed();
}, false);
}
const filterCardsByRequirementsChoosed = function(){
let numEntries = Object.entries(listForFiltering).length;
if ( numEntries === 0){
/* if there's no filter, then show all. */
for(let card of jobCards){
jobCards[card].style.display = "flex";
}
}else{
for(let card in jobCards){
jobCards[card].style.display = cardHasRequirementFilter(card)===true?"flex":"none";
}
}
};
const cardHasRequirementFilter = function(card){
for(let requirementInFilter in listForFiltering){
let requirementsByCard = jobCards[card].getElementsByClassName("job-requirements__requirement");
for(let requirementInCard in requirementsByCard){
if(requirementInCard.innerHTML === requirementInFilter.innerHTML ){
return true;
}
}
}
return false;
}

First look at the filterCardsByRequirementsChoosed function. You have both for-of and for-in loops, but are using them as though they're the same.
The for-of should be:
for(let card of jobCards){
// jobCards[card].style.display = "flex";
card.style.display = "flex";
}
The for-in was done correctly, but using for-of is a little nicer IMO.
So it seemed you were just passing the wrong value to the function in question.
Actually, I do see that you're only calling the problem function in the for-in loop, and are passing the property name. So you seem to be doing that correctly.
One thing to keep in mind is that your jobCards is a "live list". So if any of those elements get removed from the DOM, or even if the class you used to fetch them gets removed, those elements will be also removed from the jobCards list immediately.

in your loop
for(let card of jobCards)
card is your variable that will represent the elements in jobCards as they are being iterated through. It is not an index.
So you need to do
card.getElementByClassName(...)
card.style.display(...)
EDIT—
As per the comment below... you use the for in loop... which iterates over properties of the object. For an array... this will include the indices and other properties such as #length, etc giving you the error.

Related

Cannot append comparison value to DOM using javascript

The following function checks a form submission value against a data set. Currently, I am able to return a match using console.log. My question is, given that the function is working correctly in terms of comparison, how can I append the result to the body of my page? I attempted it with the following but could not get it to work:
function lookForMatches(){
const slugName = `${slugData.slug()}`;
for (var i = 0; i < globalArticles.length; i++) {
if(slugName === globalArticles[i]["slug"]){
const showMatches = document.createElement('div')
showMatches.innerHTML(`<p>${globalArticles[i]["slug"]}<p>`);
document.getElementById("slugResults").appendChild(showMatches);
}
else {
console.log("No Matches")
}
}
}
Any help would be much appreciated!
As others have mentioned, innerHTML is a property, not a function:
The Element property innerHTML gets or sets the HTML or XML markup contained within the element.
const content = element.innerHTML;
element.innerHTML = htmlString;
In your case, your code should look like this:
function lookForMatches() {
const slugName = `${slugData.slug()}`;
for (var i = 0; i < globalArticles.length; i++) {
if (slugName === globalArticles[i]["slug"]) {
const showMatches = document.createElement("div");
// Set's the inner HTML
showMatches.innerHTML = `<p>${globalArticles[i]["slug"]}</p>`;
document.getElementById("slugResults").appendChild(showMatches);
} else {
console.log("No Matches");
}
}
}

getElementById check multiple conditions

I am trying to build a function that checks if all fields are populated, if populated then show div if not hide.
I can get this to work on one fields however i have then tried two ways of checking multiple.
first
if first condition met I then ran other condition checking second field nested inside the first... this done not work.
second
I passed in an array of ID's rather than a single... this did not work either..
I am left with a working function that only works if first filed is populated can anyone think of a solution to this or maybe i passed in my array incorrectly.
My code
var myVar = setInterval(myTimer, 10);
function myTimer() {
if(!document.getElementById('Email').value) { // I need this to pass if multiple id's
var divsToHide = document.getElementsByClassName("somediv"); //divsToHide is an array
for(var i = 0; i < divsToHide.length; i++){
divsToHide[i].style.visibility = "hidden"; // or
divsToHide[i].style.display = "none"; // depending on what you're doing
}
}
else {
var divsToHide = document.getElementsByClassName("somediv"); //divsToHide is an array
for(var i = 0; i < divsToHide.length; i++){
divsToHide[i].style.visibility = "visible"; // or
divsToHide[i].style.display = "block"; // depending on what you're doing
}
}
}
Make it so your function takes an argument of the element ID and the class Name you need to check for.
Also, never use .getElementsByClassName() (read here for why). Instead, use .querySelectorAll().
And, you can use the modern .forEach() API of arrays and node lists (not in IE though), which is simpler than managing traditional for loops with indexes.
Lastly, use pre-made CSS classes instead of inline styling.
// You just need to pass the ID and Class to the following line
var myVar = setInterval(function(){ myTimer([id here],[class here]) }, 10);
function myTimer(id, class) {
// Set up these references just once and the rest of the code
// will be easier to read
var elem = document.getElementById(id);
var divsToHide = document.querySelectorAll("." + class);
// Instead of negative logic, reverse the if branches
if(elem.value) {
divsToHide.forEach(function(){
this.classList.remove("hidden"); // Much simpler than inline styling
});
} else {
divsToHide.forEach(function(){
this.classList.add("hidden");
});
}
/* Use pre-made CSS classes instead of inline styling */
.hidden { display:none; }
If you have an array of the IDs such as
let idArray = ['foo', 'bar', 'baz']
You can iterate through an array using a for loop
for (i = 0; i > idArray.length; i++) {
if (!document.getElementById(idArray[i]).value) {
// your hide logic
} else {
// your show logic
}
}
You can create a const of all elements that need to validate. For example,
const elementIdsToBeValidated = ['name', 'email'];
You can also create validator functions that returns true and false based on input,
const nameValidator = (val) => !!val;
const emailValidator = (email) => !!email;
const validators = [nameValidator, emailValidator];
Then you can run your timer function,
var myVar = setInterval(myTimer(['name', 'email']), 10);
function myTimer(ids) {
ids.forEach(id => {
const el = document.getElementById(id);
const val = el.value;
const divEl = document.getElementById('error');
const valid = validators.reduce((acc, validator) => validator(val), false);
if(valid) {
divEl.style.display = 'none';
} else {
divEl.style.display = 'block';
}
});
}
You can look at this stackBlitz example,
https://stackblitz.com/edit/js-ie7ljf

Underscorejs 'find' not working as expected

I use the following code, in a nodejs app, to build a tree from an array of database rows that form an adjacency list:
// Lay out every node in the tree in one flat array.
var flatTree = [];
_.each(rows, function(row) {
flatTree.push(row);
});
// For each node, find its parent and add it to that parent's children.
_.each(rows, function(row) {
// var parent = _.find(flatTree, function(p) {
// p.Id == row.ParentId;
// });
var parent;
for (var i = 0; i < flatTree.length; i++){
if (flatTree[i].Id == row.ParentId) {
parent = flatTree[i];
break;
}
};
if (parent){
if (!parent.subItems) {
parent.subItems = [];
};
parent.subItems.push(row);
}
});
I expect the commented out _.find call to do exactly the same as what the work-around for loop below it does, but _.find never finds the parent node in flatTree, while the for loop always does.
Similarly, a call to _.filter just doesn't work either, while the substitute loop does:
// var rootItems = _.filter(flatTree, function (node) {
// //node.ParentId === null;
// node.NoParent === 1;
// })
var rootItems = [];
for (var i = 0; i < flatTree.length; i++){
if (flatTree[i].ParentId == null){
rootItems.push(flatTree[i]);
}
}
I am using the underscore-node package, but have tried and had the same results with the regular underscore package.
Just missed the return.
var parent = _.find(flatTree, function(p) {
return p.Id == row.ParentId; // Return true if the ID matches
^^^^^^ <-- This
});
In your code nothing is returned, so by default undefined will be returned and parent will not contain any data.

Javascript object functions not working

I'm not really sure why my code isn't running correctly.. what I'm trying to do is create a grocery list object that has a couple of functions to add and remove items..
I can instantiate the objects with new items but my functions don't seem to work for some reason.
If you could save me the few hairs left in my head and tell me where the issue is I would greatly appreciate it.
var groceryList = function(itemNames,quantity) {
if (Array.isArray(itemNames)) {
this.items = itemNames;
this.quantity = quantity
this.addItems = function(newItems){
if ( Array.isArray(newItems) ) {
this.items.concat(newItems);
} else {
console.log("Please enter the items in an array fashion!");
};
};
this.removeItem = function(name) {
var listSize = this.items.length;
for (var i = 0; i < listSize; i++) {
if (this.items[i] == name) {
this.items.splice(i,1);
break;
} else {
console.log("Please enter the items in an array fashion!")
};
};
};
} else {
console.log("Please enter the items in an array fashion!")
};
};
.concat() returns a new array so you have to assign the result back to your instance variable.
So this:
this.items.concat(newItems);
needs to be changed to this:
this.items = this.items.concat(newItems);
or, you could actually use this to append to the array directly:
this.items.push.apply(this.items, newItems);
Because .push() can take more than one argument.
Then, in your .removeItem() function, you need to remove the item you actually found by changing this:
this.items.splice(2,1);
to this:
this.items.splice(i,1);

foreach object looping adding on top of the stack

I have an js, object which is something like this:
function test{
this.variable = {};
this.populate = function(){
// do some crap....
// and i populate the object like this
this.variable{xyz..} = new object();
}
this.outputThecrap(){
for (var key in data) {
if (data.hasOwnProperty(key)) {
if(data[key].idParent != '0'){
//do some stuff
}
}
}
}
this.addSomeOnBeginigQQ(){
// how do i do that!!!!Q_Q
this.variable{blabla...} = new blabla();
}
}
now after I populate the object like
var t = new test();
t.populate();
t.addSomeOnBegining();
t.outputThecrap();
I get the problem that the added properties wind up on the end of the loop ... and I need them to be on the top
Anyone has some idea how to solve this?
UPDATE:
The structure of the object is not open to change. i cant use the array as a container either, that s out of question.
If you want a stack, you will need to use an Array - a list with a defined order. Object properties have none in JavaScript, there is nothing like "associative arrays". Also, you should the prototype.
You can set properties of array just as you do with objects, but the property names need to be numerically (i.e. integers). You then loop over them with a for-loop. Array objects also have some extra methods, for example to add items in the beginning or the end (which I have used below):
function Test() {
this.data = []; // an array
}
Test.prototype.populate = function(){
// populate the array like this
this.data.push({…});
};
Test.prototype.outputThecrap = function(){
for (var i=0; i<this.data.length; i++) {
var item = this.data[i];
if (item /* has the right properties*/)
//do some stuff
}
};
Test.prototype.addSomeOnBeginning(){
this.data.unshift({…});
};
Then use it like this:
var t = new Test();
t.populate();
t.addSomeOnBeginning();
t.outputThecrap();
The "ordered key array" looks like this:
function Test() {
this.data = {}; // the object
this.order = []; // an array
}
Test.prototype.populate = function(){
this.data["something"] = {…}
this.order.push("something");
};
Test.prototype.addSomeOnBeginning(){
this.data["other"] = {…};
this.order.unshift("other");
};
Test.prototype.outputThecrap = function(){
for (var i=0; i<this.order.length; i++) {
var key = this.order[i],
item = this.data[key];
if (item && key /* fulfill your requirements */)
// do some stuff
}
};

Categories