How to map API with multiple objects in [Javascript, ES6] - javascript

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
})`

Related

Attaching an index of one array to the index of another array

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>

Return multiple elements from a function number property

Is there a way i can return multiple elements from a function based off a number property that it ingests? For example: I have an element of a coin, which is just a <div className="coin"></div>" and I'd like to have a function where I can say {displayCoins(5)}, and the param it takes is the number of coins to return.
What I've tried so far is the following
const displayCoins = (numberOfCoins) => {
let elCoin = document.createElement('div')
elCoin.className = "coin"
return elCoin * numberOfCoins
}
Thank you
If you want to return multiple elements you can return an array of them. You don't need to create DOM elements manually with document.createElement('div'), you can simply create them, or template them specifically, in JSX.
const displayCoins = (numberOfCoins) => {
return [...Array(numberOfCoins).keys()].map(el => (
<div key={el} className="coin">
));
}

Why am I seeing repeated values for both columns on my table even though I'm using a Set?

Hey can anyone tell me why I'm getting repeated values for both oppDesc and contestEntriesAmt even though I'm using a Set for oppDesc (contestEntriesAmt doesn't need to be in a Set because nothing's being repeated)?
Why are both oppDesc and contestEntriesAmt repeating? It just doesn't make sense.
Whenever I remove entries.map(() => {...}), oppDesc shows up correctly (no repeated values).
const oppDescData = () => {
const dataOppDesc = oppDesc
let desc = [];
dataOppDesc.forEach((oppD) => {desc.push(oppD.oppDescription);});
const dataNumEntries = numEntries
let entries = [];
dataNumEntries.forEach((entry) => {entries.push(entry.SumOfEntries);});
let filteredDesc = new Set(desc);
let oppDescription = [...filteredDesc];
return (
<>
{
oppDescription.map((oppDesc) => {
return entries.map((contestEntriesAmt) => {
return(
<tr>
<td>{oppDesc}</td>
<td>{contestEntriesAmt}</td>
</tr>
);
})
})
}
</>
);
};
You getting duplicates as you are doing intersection of two lists by calling map in map. Says you have two lists, each 10 items, in result with your code you will get 100 tr entries. Even if you will use sets, and each value will be unique per array - this still will happens

For loop a number to create buttons inside template literal

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?

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>

Categories

Resources