The idea I'm trying to do is, let's say I have some DOM elements and I want to create a function that accepts 2 arrays, one for the elements and another for the class names. How I make sure that element at index 0 for example only has the class name I pass at index 0 of the other array.
Here is a visual of what I'm trying to do
function addClassName(arrOfElements, arrOfClassNames) {
// Here is what ive tested
arrOfElements.forEach((el) => {
el.classList.add(arrOfClassNames);
});
}
Expected Result
addClassName([el1, el2], ["class-for-el1", "class-for-el2"]
console.log(el1.classList);
// Result: "class-for-el1"
console.log(el2.classList);
// Result: "class-for-el2"
<div class="class-for-el1"></div>
<div class="class-for-el2"></div>
What i get instead
console.log(el1.classList);
// Result: "class-for-el1", "class-for-el2"
console.log(el2.classList);
// Result: "class-for-el2", "class-for-el2"
<div class="class-for-el1 class-for-el2"></div>
<div class="class-for-el1 class-for-el2"></div>
If number of items of arrOfElements and arrOfClassNames is the same, you can do smthing like:
function addClassName(arrOfElements, arrOfClassNames) {
// Here is what ive tested
arrOfElements.forEach((el, index) => {
el.classList.add(arrOfClassNames[index]);
});
}
Array.prototype.forEach() callback gives you two parameters, first one being the element itself and second one being its index, you can use this property to achieve what you wanted like this
const el1 = document.getElementById('1'),
el2 = document.getElementById('2');
function addClassName(arrOfElements, arrOfClassNames) {
arrOfElements.forEach((el, index) => {
el.classList.add(arrOfClassNames[index]);
});
}
addClassName([el1, el2], ['test', 'test1']);
console.log(`class for el1 - ${el1.className}\n`);
console.log(`class for el2 - ${el2.className}`);
<div id="1"></div>
<div id="2"></div>
You can simply use array index to get the class name and add it
el.classList.add(arrOfClassNames[i]);
Note: There are 3 arguments that are passed to the callback function
1) element: The current element being processed in the array.
2) index (Optional): The index of element in the array.
3) array (Optional): The array forEach() was called upon.
function addClassName(arrOfElements, arrOfClassNames) {
// Here is what ive tested
arrOfElements.forEach((el, i) => {
el.classList.add(arrOfClassNames[i]);
});
}
const [el1, el2] = document.querySelectorAll("div");
addClassName([el1, el2], ["class-for-el1", "class-for-el2"]);
console.log(el1.classList);
// Result: "class-for-el1"
console.log(el2.classList);
// Result: "class-for-el2"
<div>First</div>
<div> second </div>
Related
trying to push data coming to "id" to "selectedUserId" array, but first element is not inserting.
selectedUserId array does not contain first pushed element, push is only working from second element onwards.
const handleSelectOne=(e)=>{
const id = e.target.value;
console.log(id,"handling")
if(!selectedUserIds.includes(id))
{
selectedUserIds.push(id)
}
else
{
selectedUserIds.pop(id)
}
setCheckedStatusOne(!checkedStatusOne[id])
}
const handleDeleteSelectedClick=() =>{
let deletionItemsNo = selectedUserIds.length
selectedUserIds.map((id)=>{
return console.log(id, "<== element inside selecteduserids array")
})
console.log(deletionItemsNo, "<== number of elements in array")
}
output
console output
.pop() method doesn't accept any arguments. It used for removing the last array item.
To be able to insert element in the beginning you should use .unshift(id)
I am working on the domain API I would like to display domain names and prices at the same time but They are in two different object. I always get undefined when I use this. So If I dataArray[0] or dataArray[1] can get all the result only cannot get both. Thank you for the help.
domain.Name inside of data.Domains object
domain.PriceInfo inside of data.Prices object.
const displayDomains = (data) => {
const dataArray = [data.Domains, data.Prices];
const htmlString = dataArray[(0, 1)]
.map((domain) => {
return `<div class="domains">
<h2>${domain.Name}</h2>
<div class="domain-price-container">
<sub class="discount-price">${domain.PriceInfo}</sub>
</div>
</div>`;
})
.join('');
If data.Domains and data.Prices are equal length arrays, then a straight forward workaround would be to simply loop over both arrays with common index,
const dataArray = [data.Domains, data.Prices];
let index = 0;
let htmlString = [];
for(index; index < sizeOfArray; index++) {
htmlString.push(
<div class="domains">
<h2>${dataArray[0][index].Name}</h2>
<div class="domain-price-container">
<sub class="discount-price">${dataArray[1][index].PriceInfo}</sub>
</div>
</div>
);
}
If both arrays have different sizes, insert all common elements upto smaller sizes out of two, and next insert leftover elements.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/map
The second argument passed into the .map callback is the index. That allows you to do something like this:
data.Domains.map((domain, index) => {
const price = data.Prices[index];
return <>; // whatever JSX you want here, including both domain and price information
})`
Getting a bit stuck with this one.
I'm looping through an object (dataLayer.Tests) and I'm displaying the values of my content, in a DIV. Here's an example of how this object looks:
I'm doing this by looping through my object with forEach. (And in this example, I'm just console.logging my result result3).
The problem I'm having, is that within my forEach, I want to display create/display buttons, depending on what the number is in the totalVariants key/value.
So for example, if the totalVariants === 2, I want to create 2 buttons. If it is one, I want to create 1 button.
I know I need to for loop through this particular value, but I'm not sure how to do this, within a template literal.
Here's my code.
dataLayer.Tests.forEach((element, index, array) => {
let result3 = '';
let numberOfVariants = element.totalVariants;
if (numberOfVariants >= 1) {
for (i = 0; i < numberOfVariants; i++) {
console.log("The number is ", i + 1);
}
result3 += `
<div class="CRO-variant-result">
<p>Date Launched: ${element.date}</p>
<p>Test ID: ${element.id}</p>
<p>Test Description: ${element.name}</p>
<p>Variant Active: ${element.variant}</p>
<p>Total Variants: ${element.totalVariants}</p>
${(function () {
for (i = 0; i < element.totalVariants; i++) {
return `<button>${i}</button>`
}
})()}
</div>
`
console.log("result3", result3);
};
});
I've seen solutions which include .map and object.keys, but this doesn't seem to work/return anything. (Probably as I just need to loop through a number and not array etc.
Any ideas/pointers, would be appreciated.
Basically, I'm not sure how to loop through a number, within a template literal and return x number of elements.
Thanks,
Reena
numberOfVariants is an number, not an object, so one way you could do this is create a new incrementing array of that length (Array.from(Array(numberOfVariants).keys()) does this nicely) and then map over that array as you're doing.
${Array.from(Array(numberOfVariants).keys()).map(i => (
`<button value="${i}">${i}</button>`
)).join('')}
I'm not quite sure what you want to appear inside the button (maybe the integer of the current number as you increment)?
How to get all classes containing hyphen/dash(?) applied to any DOM element and save them into array in JavaScript ?
My failing approach:
var getClasses = [];
var classesContain = [];
document.querySelectorAll('*').forEach( x => {
var y = x.className.split(' ');
getClasses.push(y);
});
getClasses.forEach( c => {
if(c.contains('-')){
classesContain.push(c);
}
});
Your attempt is fairly close to working. The problem is you're pushing an array into getClasses rather than the individual classes, and neither strings nor arrays have a standard contains method (there's includes, which is probably what you mean). Also, if you only want ones containing -, you can filter them out earlier:
let classesWithDash = new Set();
document.querySelectorAll('*').forEach(element => {
for (const cls of element.className.split(' ').filter(name => name.includes("-"))) {
classesWithDash.add(cls);
}
});
// Now, `classesWithDash` is a set containing the class names with dashes
// If you want an array:
classesWithDash = [...classesWithDash];
Live Example:
let classesWithDash = new Set();
document.querySelectorAll('*').forEach(element => {
for (const cls of element.className.split(' ').filter(name => name.includes("-"))) {
classesWithDash.add(cls);
}
});
// Now, `classesWithDash` is a set containing the class names with dashes
// If you want an array:
classesWithDash = [...classesWithDash];
console.log(classesWithDash);
<div class="foo foo-bar"></div>
<div class="another-one"></div>
<div class="nodash"></div>
(I have never understood why Set doesn't have an addAll method, or at least accept multiple values to add like push does...)
Use document.querySelectorAll() with an attribute selector to get all elements with a class that includes (=*) an hyphen. Convert the results to an array using Array.from(). Now iterate the elements with Array.flatMap(), get the classlist and convert to an array, and filter out classes that don't include a hyphen. Use a Set to make the items unique, and spread back to an array.
const result = [...new Set( // use a Set to get an array of unique items
Array.from(document.querySelectorAll('[class*="-"]')) // select all elements with classes that contain hyphens
.flatMap(el => Array.from(el.classList).filter(c => c.includes('-'))) // create an array of all classes with hyphens
)]
console.log(result)
<div class="something a-b something-else x-y"></div>
<div class="something"></div>
<div class="a-b c-d"></div>
The thing you are not realizing is that you are pushing an array of classes into your getClasses array. So you end up with an array of arrays, a.k.a. a 2-dimensional array.
Note, too, that you can do your extracting of classes and filtering to only those that contain dashes in one step, rather than having to process the list twice.
var classesContain = [];
document.querySelectorAll('*').forEach(x => {
var y = (x.className || '').split(/\s+/g); // use a regex to cater for multiple spaces
y.forEach(className => {
if (className.includes('-'))
classesContain.push(className);
});
});
console.log('Final class list: ', classesContain);
<div class="foo-bar bar-baz foo">
<div class="foo-baz">
<span class="single">Example markup</span>
</div>
</div>
I have a div, with lots of other divs inside, each with a button inside that. I need to order the divs inside the main div, based on their id, but without using jQuery or anything, just clean and simple JavaScript. I can't find any way to do this, so any suggestions would be greatly appreciated.
I have been on lots of websites that show solutions for doing it based on the text within the div but not by the id.
function sortDiv() {
var mainDiv = document.getElementById("divsGroup");
var divs = mainDiv.children;
for (i = 0; i < divs.length(); i++) {
if //divs[i] is higher in the alphabet than divs[i+1] then {
//rearrange the divs
};
};
};
I need the divs to be rearranged so they're displayed based on their id, alphabetically.
Here's a solution where the sorting bit is handled in a simple Array of id strings. Then, for each id (already in alphabetical order), we loop through the divs to find the next one to (re-)insert into the DOM.
document.getElementById("sortBtn").addEventListener("click", sortDivs);
function sortDivs(){
let mainDiv = document.getElementById("divsGroup"),
divs = mainDiv.children,
// `[...divs]` converts `divs` to an Array so we can use the `.map` and `.sort` methods
divsArray = [...divs];
// `.map(div => div.id )` makes a new Array of all the `id` strings, and
// `.sort()` sorts the new Array alphabetically
idList = divsArray.map(div => div.id).sort();
//console.log(idList); // logs ["a", "b", "c", "d" ]
// `idList` and `divsArray` are Arrays, so we can also use
// the `.forEach` method to loop through them
idList.forEach(id => {
// As we process each `id` alphabetically, we check each `div`'s id for a match
divsArray.forEach(div => {
if(div.id == id){ // Finds div with matching id
mainDiv.appendChild(div); // Moves the matching div to bottom of `mainDiv`
}
});
});
}
<div id="divsGroup">
<div id="d">-d-</div>
<div id="b">-b-</div>
<div id="c">-c-</div>
<div id="a">-a-</div>
</div>
<button id="sortBtn">Sort 'em</button>
Note: This code could be shorter, but for anyone unfamiliar with the .map and .forEach methods of Array, or with the spread operator (...), this lengthier version may help make things more clear.
You can use javascript arrays sort to sort nodes like this:
<div id="main">
<div id="9"><button>9</button></div>
<div id="2"><button>2</button></div>
<div id="3"><button>3</button></div>
<div id="4"><button>4</button></div>
<div id="5"><button>5</button></div>
<div id="1"><button>1</button></div>
<div id="6"><button>6</button></div>
<div id="7"><button>7</button></div>
<div id="8"><button>8</button></div>
</div>
let parentNode = document.getElementById("main");
var e = parentNode.children;
[].slice
.call(e)
.sort(function(a, b) {
return a.id.localeCompare(b.id);
})
.forEach(function(val, index) {
parentNode.appendChild(val);
});
Like this you can sort by any attribute, for example you can sort by textContent of those elements or any other property.
here's a pen: https://codepen.io/wyzix33/pen/XvpWBg
Hope it helps
mainDiv.children returns an HTMLCollection
Convert that to an Array and perform a sort
Array.from(divs).sort((a,b) => a.id > b.id ? 1 : -1)
Then loop through to move them into the divsGroup in order using appendChild
Array.from(divs).sort((a,b) => a.id > b.id ? 1 : -1).forEach(ele => {
mainDiv.appendChild(ele);
});
jsfiddle
Resulting sortDiv() function:
function sortDiv() {
var mainDiv = document.getElementById("divsGroup");
var divs = mainDiv.children;
Array.from(divs).sort((a,b) => a.id > b.id ? 1 : -1).forEach(ele => {
mainDiv.appendChild(ele);
});
};
Alternatively, if you need the list copied to a new element instead of moved use cloneNode([deepcopy])
Array.from(divs).sort((a,b) => a.id > b.id ? 1 : -1).forEach(ele => {
someOtherDiv.appendChild(ele.cloneNode(true));
});