New to JS. All of the questions I could find with similar titles to mine were a bit too complicated for me to understand.
Simply put, I am trying to loop through an array and return one result at the end that essentially adds/concatenates all of the values of the array together.
However, I can't seem to get it to work, as the items in the array are blocks of HTML code, rather than simple strings or numbers. Here's a dumbed-down version.
HTML:
<article class="wrapper"><p>Some text 1.</p></article>
<article>No class.</article>
<article class="wrapper"><p>Some text 2.</p></article>
<article>No class.</article>
<article class="wrapper"><p>Some text 3.</p></article>
I am trying to figure out a way to end up with a template literal of this code:
<article class="wrapper"><p>Some text 1.</p></article>
<article class="wrapper"><p>Some text 2.</p></article>
<article class="wrapper"><p>Some text 3.</p></article>
So that I can inject the entire thing as the innerHTML of another element on a different page.
Started with this JS:
articleArray = document.querySelectorAll('.wrapper').outerHTML;
console.log(articleArray)
// This will return an array with the full HTML of the 3 "wrapper" articles as each item
Then tried to create a loop that will take the full HTML of item 1 on first loop and set it as something like an accumulator value. Then on second loop, it would take the full HTML of item 2 and concatenate it directly to item 1, and that would be the new accumulator value. And so on.
I have far more than 3 items for what I'm applying this to in real life, otherwise I could just do something like articleArray[0] + articleArray[1] + articleArray[2].
I tried a million things, but here were the closest attempts:
var articleArray = document.querySelectorAll('.wrapper').outerHTML;
for (i = 0; i < searchWrappers.length; i++) {
searchWrapper = articleArray[i];
console.log(searchWrapper);
}
// Console log brought back 3 objects, but I need to combine them
var articleArray = document.querySelectorAll('.wrapper').outerHTML;
var searchStr = ''
for (i = 0; i < articleArray.length; i++) {
itemHTML = articleArray[i];
fullString = searchStr += itemHTML;
console.log(fullString);
}
// This did concatenate the 3 items, but only as:
// [object HTMLElement][object HTMLElement][object HTMLElement]
// and not the actual HTML
const articleArray = document.querySelectorAll('.wrapper').outerHTML;
const sum = articleArray.reduce((accumulator, value) =>
$(accumulator).concat($(value)));
console.log(sum);
// This brought back a normal array of the 3 items again
Any help appreciated!
Edit: Thanks for all your responses! I am going to go through them now and testing your solutions on my real code to see what works best.
You can't write anything that's not a simple expression inside of a template literal, so no if statements or loops. You can use ternary expressions, however, if you need to make a choice: var quantity = 14; var cart = `You have ordered ${quantity} ${quantity > 1 ? "wheels" : "wheel"} of cheese.
Backticks ( ` ) are used to define template literals. Template literals are a new feature in ECMAScript 6 to make working with strings easier. Features: we can interpolate any kind of expression in the template literals. They can be multi-line.
The ${} syntax allows us to put an expression in it and it will produce the value, which in our case above is just a variable that holds a string! There is something to note here: if you wanted to add in values, like above, you do not need to use a Template Literal for the name variable.
we can't embed loop inside a string literal but yes we can call a function. Thanks for contributing an answer to Stack Overflow! Please be sure to answer the question.
JavaScript : Array literals. In Javascript, an array literal is a list of expressions, each of which represents an array element, enclosed in a pair of square brackets ' [ ] ' . When an array is created using an array literal, it is initialized with the specified values as its elements, and its length is set to the number of arguments specified.
Number literals can be written with or without decimal places. Number literals can be either positive numbers or negative numbers. If you do not specify a sign, then a positive number is assumed. Here are some examples of valid number literals: In JavaScript, you can declare a variable named counter and give it the numeric value of 15.
JavaScript supports different kinds of loops: for - loops through a block of code a number of times for/in - loops through the properties of an object while - loops through a block of code while a specified condition is true do/while - also loops through a block of code while a specified condition is true
This should help you:
function contains(selector, text) {
var elements = document.querySelectorAll(selector);
return [].filter.call(elements, function (element) {
return RegExp(text).test(element.textContent);
});
}
var articleArray = contains(".wrapper", 'menu');
// var articleArray = contains(".wrapper", /menu/i); // for case-insensitive
let templateLiteral = ``;
articleArray.forEach(function (article) {
templateLiteral += article.outerHTML + '\n';
})
console.log(templateLiteral);
article {
display: none;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
</head>
<body>
<article class="wrapper"><p>Some text 1. menu</p></article>
<article>No class.</article>
<article class="wrapper"><p>Some text 2. menu</p></article>
<article>No class.</article>
<article class="wrapper"><p>Some text 3.</p></article>
</body>
</html>
The basic idea is to loop through each HTML element and get add the outerHTML
of the element to the template literal.
Edit: Thanks to this answer, it helps me achieve the desired effect of finding a vanilla js replacement for :contains
in jQuery.
You could map the elements to their outer HTML and then join the results.
const htmlString = [...document.querySelectorAll('.wrapper')]
.map(({ outerHTML }) => outerHTML.trim())
.join('\n');
console.log(htmlString);
.as-console-wrapper { top: 0; max-height: 100% !important; }
.wrapper { display: none; }
<article class="wrapper">
<p>Some text 1.</p>
</article>
<article>No class.</article>
<article class="wrapper">
<p>Some text 2.</p>
</article>
<article>No class.</article>
<article class="wrapper">
<p>Some text 3.</p>
</article>
You can also fetch only wrappers and push them in new element to make a template:
let result = document.createElement("div")
document.querySelectorAll('.wrapper').forEach(e =>
result.insertAdjacentElement("beforeend", e))
console.log(result.innerHTML)
<article class="wrapper">
<p>Some text 1.</p>
</article>
<article>No class.</article>
<article class="wrapper">
<p>Some text 2.</p>
</article>
<article>No class.</article>
<article class="wrapper">
<p>Some text 3.</p>
</article>
Then you can use result.innerHTML
to transfer all.
Also see: Element.insertAdjacentElement()
EDIT: You will actuality need to use cloning so wrappers does not get removed from DOM:
let result = document.createElement("div")
document.querySelectorAll('.wrapper').forEach(e => {
let cln = e.cloneNode(true)
result.insertAdjacentElement("beforeend", cln)
})
console.log(result.innerHTML)
<article class="wrapper">
<p>Some text 1.</p>
</article>
<article>No class.</article>
<article class="wrapper">
<p>Some text 2.</p>
</article>
<article>No class.</article>
<article class="wrapper">
<p>Some text 3.</p>
</article>
DOMParser is the right tool if you really have:
"the items in the array are blocks of HTML code"
// I have an array of elements as HTML strings:
const elArray = [
`<article class="wrapper"><p>Some text 1.</p></article>`,
`<article>No class.</article>`,
`<article class="wrapper"><p>Some text 2.</p></article>`,
`<article>No class.</article>`,
`<article class="wrapper"><p>Some text 3.</p></article>`,
];
// DOMParser is the right tool for the job!
const DOC = new DOMParser().parseFromString(elArray.join(""), "text/html");
// Use selectors as normal!
const ELs = DOC.querySelectorAll(".wrapper");
// DEMO TIME: retrieve elements and finally
// place them somewhere in the app
document.querySelector("#test").append(...ELs);
<div id="test"></div>
If instead you actually have a NodeList of Elements:
// I am trying to figure out a way to end up
// with a template literal!
const ELs = document.querySelectorAll("article.wrapper");
const literal = [...ELs].reduce((s, EL) => s + EL.outerHTML, "");
console.log(literal);
<article class="wrapper"><p>Some text 1.</p></article>
<article>No class.</article>
<article class="wrapper"><p>Some text 2.</p></article>
<article>No class.</article>
<article class="wrapper"><p>Some text 3.</p></article>
Depends on what you're actually building, you need to be aware that when taking items from the DOM and converting them to string you might lose any Element
Properties or Events (like "click"
etc) assigned to those elements.
In such case you might just want to perhaps simply use Element.append(...myNodesList)
to move them to your desired new location in the DOM:
// Let's say they have some event listeners already assigned:
document.querySelectorAll(".wrapper").forEach(EL => EL.addEventListener("click", (ev) => {
console.log(ev.currentTarget.textContent);
}));
// Get your elements
const ELs = document.querySelectorAll("article.wrapper");
// And simply move them somewhere else!
document.querySelector("#test").append(...ELs);
// Click events are preserved!!
#test { padding: 10px; background: #eee; }
<article class="wrapper"><p>CLICK ME! 1.</p></article>
<article>No class.</article>
<article class="wrapper"><p>CLICK ME! 2.</p></article>
<article>No class.</article>
<article class="wrapper"><p>CLICK ME! 3.</p></article>
<div id="test">
<!-- Let's say you want to insert your .wrapper elements here! -->
</div>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With