Javascript reorder HTML element based on attribute value - javascript

I have the following HTML:
<div class="wrapper">
<div class="item" id="item-1">
</div>
<div class="item" id="item-2">
</div>
<div class="item" id="item-3">
</div>
</div>
And in javascript I'm currently applying filters & sort to the results of an array:
results = Object.keys(list).filter(.....);
results = results.sort((a, b) => (....) ? 1 : -1);
// After the results have been filtered & sorted, hide all HTML elements:
document.querySelectorAll('.item').forEach(i => i.classList.add('d-none'));
// And then proceed to show only the results that have been filtered & sorted:
results.forEach(index =>
{
let id = list[index].id;
let item = document.getElementById('item-' + id);
item.classList.remove('d-none');
});
This works great. The problem is that now I need to move the HTML elements according to the results array, specifically with the id field.
A) Expected output: Array ids [2, 1]
<div class="wrapper">
<div class="item" id="item-2">
</div>
<div class="item" id="item-1">
</div>
<div class="item d-none" id="item-3">
</div>
</div>
B) Expected output: Array ids [2]
<div class="wrapper">
<div class="item" id="item-2">
</div>
<div class="item d-none" id="item-1">
</div>
<div class="item d-none" id="item-3">
</div>
</div>

You can move elements to the top, using prepend function.
On bellow example, I only implement the logic about move elements, and I didn't protected against non existent elements.
You should add your logic's about filtering, etc. and protect for possible errors.
function sortDivs() {
let list = [2, 1];
let mainDiv = document.querySelectorAll('.wrapper')[0];
list.reverse().forEach(n => mainDiv.prepend(document.getElementById('item-'+n)));
}
.item {
border: black solid;
}
<div class="wrapper">
<div class="item" id="item-1">
item-1
</div>
<div class="item" id="item-2">
item-2
</div>
<div class="item" id="item-3">
item-3
</div>
</div>
<br>
<button onClick="sortDivs()"> sort DIVs</button>

One way would be to
iterate the result ids and get the correspondig object from the dom (combined with your last .forEach round removing the d-done class)
get all d-done elements and combine both lists
convert to html and reset innerHTML of the wrapper
let results = [2,1]
let wrapper = document.getElementById('wrapper-id')
wrapper.innerHTML = results.map(id => document.querySelector('#item-' + id))
.concat([...document.querySelectorAll('.d-none')])
.map(elem => elem.outerHTML)
.join('')
<div class="wrapper" id="wrapper-id">
<div class="item" id="item-1">
item-1
</div>
<div class="item" id="item-2">
item-2
</div>
<div class="item d-none" id="item-3">
item-3
</div>
</div>

Solved.
I had several problems:
The first one was instead of using Object.keys(results).filter I should be using results.filter, because I don't need to get only the Keys, which was making things way harder.
Secondly, the logic to apply in order to have everything re-organizing according to multiple filters is:
Sort / filter everything
Hide all items (using d-none)
Grab all the wrapper children const wrapperItems = wrapper.children
Create a variable named wrapperNewItems that holds the new sorted/filtered items
Create a variable that holds which ID's (item-1, item-2, etc) have been sorted/filtered
Push the items sorted into the variable and remove d-none
Push the items that were NOT sorted into the variable and keep d-none
Translated into code:
document.querySelectorAll('.item').forEach(i => i.classList.add('d-none'));
const wrapper = document.getElementsByClassName('wrapper')[0];
// Saves the existing children
const wrapperItems = wrapper.children;
// Holds the new items ordered perfectly
let wrapperNewItems = [];
// Holds names that were filtered (item-1, item-2, etc)
let listOfNamesFiltered = [];
// Shows only the items filtered
results.forEach(item =>
{
let name = 'item-' + item.id;
let el = document.getElementById(name);
el.classList.remove('d-none');
wrapperNewItems.push(el);
listOfNamesFiltered.push(name);
});
for (let i = 0; i < wrapperItems.length; i++)
{
let item = wrapperItems[i];
let name = item.id; // id="" already contains "item-{id}"
// If the name already exists in the list, we won't add it again
if (listOfNamesFiltered.includes(name))
continue;
wrapperNewItems.push(item);
}
// Clears the div
wrapper.innerHTML = '';
// Appends the items once again
for (let i = 0; i < wrapperNewItems.length; i++)
wrapper.innerHTML += wrapperNewItems[i].outerHTML;

Related

Get values from ID HTML and save in array

I'm doing a view where once I click I'm displaying
For Loop
I am having a view that captures a QR code and displays it on the screen, what I want to do next is take these values by iterating the elements with a for loop and save it in an array, in this case my ID is id="scanned-result" and I want to iterate each containing values and saving to an array.
I am doing this but for some reason it is not performing the operation correctly. I would like to know what I should correct?
function SubmitCodes() {
var QRCodeval= document.querySelectorAll('scanned-result');
var arr = [];
for (var i in QRCodeval) {
alert(QRCodeval[i]);
arr.push( QRCodeval[i]);
}
alert(arr.val);
}
VIEW
<div class="container">
<div class="row">
<div class="col-md-12" style="text-align: center;margin-bottom: 20px;">
<div id="reader" style="display: inline-block;"></div>
<div class="empty"></div>
<div id="scanned-result">
<div>[1] - https://www.investopedia.com/terms/q/quick-response-qr-code.asp</div>
<div>[2] - https://www.dropbox.com/s/705b6p4a2ydvayx/EN-Poster.pdf?dl=0</div></div>
</div>
</div>
</div>
There are several issues with your code. To select element by ID using querySelector you need to use # selector, also to select the divs inside you can use element > element selector.
var QRCodeval = document.querySelectorAll("#scanned-result>div");
querySelectorAll returns a nodeList. So you need to iterate through it to get value of individual elements. But you should not use for..in. You can use forEach instead.
function submitCodes() {
var QRCodeval = document.querySelectorAll("#scanned-result>div");
var arr = [];
QRCodeval.forEach((el) => arr.push(el.innerHTML));
console.log(arr)
}
submitCodes();
<div class="container">
<div class="row">
<div class="col-md-12" style="text-align: center;margin-bottom: 20px;">
<div id="reader" style="display: inline-block;"></div>
<div class="empty"></div>
<div id="scanned-result">
<div>[1] - https://www.investopedia.com/terms/q/quick-response-qr-code.asp</div>
<div>[2] - https://www.dropbox.com/s/705b6p4a2ydvayx/EN-Poster.pdf?dl=0</div>
</div>
</div>
</div>
</div>
To get the text inside of the elements you can use innerHTML.
Since there is no <scanned-result></scanned-result> element on your page, as charlietfl pointed out, you won't get any results.
Since your HTML markup is the following:
<div id="scanned-result">
<!-- … -->
</div>
You are looking for an ID.
And the valid ID query in a CSS selector is a #, because of that you should query like:
var QRCodeval = document.querySelectorAll('#scanned-result')
I've changed the iteration to fill the array with the lines inside the ID scanned-result. Would that help ?
function SubmitCodes() {
var QRCodeval = document.getElementById('scanned-result').children;
var arr = [];
for (var i = 0; i < QRCodeval.length; i++) {
arr.push(QRCodeval[i].innerText)
}
console.log(arr)
}
<div class="container">
<div class="row">
<div class="col-md-12" style="text-align: center;margin-bottom: 20px;">
<div id="reader" style="display: inline-block;"></div>
<div class="empty"></div>
<div id="scanned-result">
<div>[1] - https://www.investopedia.com/terms/q/quick-response-qr-code.asp</div>
<div>[2] - https://www.dropbox.com/s/705b6p4a2ydvayx/EN-Poster.pdf?dl=0</div>
</div>
</div>
</div>
</div>

Applying the sort method inside divs (cards) in a Single Page Application - Vanilla Javascript

I have been working on a single page application in Javascript and would like to implement a sort by names and popularity of cards created by some data fetched from Movie DB API. I have already tried to use the code below to sort the elements and append them on the page but have been struggling with it.
Thanks in advance for your time reading and helping me with this. I do really appreciate it!
const SORT = {
namesArr:[],
name:(ev)=>{
//avoiding the popstate event to be triggered
ev.preventDefault();
//getting the pages content
let page= document.querySelector('#actors');
//getting the parent Element on the page
let items= document.querySelector('.cards');
//converting the elements into an array
items= Array.prototype.slice.call(items.children);
console.log(items)
//sorting the elements
items.sort(function (a, b) {
//getting the name inside each card.
varA= a.name.toUpperCase();
varB= b.name.toUpperCase();
if (varA < varB){
return -1;
}
if (varA > varB){
return 1;
}
return 0;
});
//iterating over the elements to append it on the page.
for(i = 0; i < items.length; i++){
page.appendChild(items[i]);
}
},
};
<section id= "actors" class="active">
<div class="cards">
<div class="card" data-key="18897"><img class="picture" src="https://image.tmdb.org/t/p/w300/nraZoTzwJQPHspAVsKfgl3RXKKa.jpg"><h3 class="name">Jackie Chan</h3><p class="popularity">Popularity: 28.744</p></div>
<div class="card" data-key="1173223"><img class="picture" src="https://image.tmdb.org/t/p/w300/hkHu1Z4EtN47bPwh6PlBIE3Jz76.jpg"><h3 class="name">Danny Chan Kwok-Kwan</h3><p class="popularity">Popularity: 15.431</p></div>
</div>
</section>
I believe you want to sort the cards
const cards = document.querySelector("#actors .cards");
const children = [...cards.children];
children.sort((a, b) => {
return a.querySelector(".name").innerText > b.querySelector(".name").innerText ? 1 : -1;
})
cards.innerHTML = "";
children.forEach(item => cards.appendChild(item));
<section id="actors" class="active">
<div class="cards">
<div class="card" data-key="18897"><img class="picture" src="https://image.tmdb.org/t/p/w300/nraZoTzwJQPHspAVsKfgl3RXKKa.jpg">
<h3 class="name">Jackie Chan</h3>
<p class="popularity">Popularity: 28.744</p>
</div>
<div class="card" data-key="1173223"><img class="picture" src="https://image.tmdb.org/t/p/w300/hkHu1Z4EtN47bPwh6PlBIE3Jz76.jpg">
<h3 class="name">Danny Chan Kwok-Kwan</h3>
<p class="popularity">Popularity: 15.431</p>
</div>
</div>
</section>

How I can read styles in ul tag using loop

Is there any way to read background-color and color in styles and put it in list using javascript specifically loop ?
HTML
<ul id="list">
<li>
<div class="card">
<div class="test1" style="background-color: #fff333;"></div>
<p class="test2" style="color: #000;">#ef5777</p>
</div>
</li>
</ul>
JavaScript
<script>
var background = [];
var colors = [];
// is there any way to put background and color in one array without 2 array ?
// after that what should I do ?
</script>
If your just wanting to retrieve what's in the style attribute, then you can just use getAttribute("style") on the DOM node.
If your wanting the physical color, that also takes into account CSS, there is getComputedStyle too,.
Here is an example of the getAttribute way.
const items = document.querySelectorAll('#list *');
const styles = [];
for (const item of items) {
const st = item.getAttribute("style");
if (st) styles.push(st);
}
console.log(styles);
<ul id="list">
<li>
<div class="card">
<div class="test1" style="background-color: #fff333;">xx</div>
<p class="test2" style="color: #000;">#ef5777</p>
</div>
</li>
</ul>
And here is an example of using getComputedStyle
const items = document.querySelectorAll('#list *');
const colors = [];
const background = [];
for (const item of items) {
const c = window.getComputedStyle(item);
colors.push(c.getPropertyValue('color'));
background.push(c.getPropertyValue('background-color'));
}
console.log(colors);
console.log(background);
<ul id="list">
<li>
<div class="card">
<div class="test1" style="background-color: #fff333;">xx</div>
<p class="test2" style="color: #000;">#ef5777</p>
</div>
</li>
</ul>

Add JS array values to multiple divs

I have an array
var arr = [3,0,1,0,0];
and multiple divs.
<div class="fb0"></div>
<div class="fb1"></div>
<div class="fb2"></div>
<div class="fb3"></div>
<div class="fb4"></div>
and more.
How to add values from an array alternately by numbers in an array to div numbers by classes.
<div class="fb0">3</div>
<div class="fb4">0</div>
<div class="fb2">1</div>
<div class="fb3">0</div>
<div class="fb1">0</div>
You can use jQuery's .each() to loop through all the div. Inside event handler function use the index to take the item from the array and set the text of the current element:
var arr = [3,0,1,0,0];
$('[class^=fb]').each(function(idx){
if(arr.length >= idx) // check if the array length is grater/equal to the current index.
$(this).text(arr[idx]);
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="fb0"></div>
<div class="fb1"></div>
<div class="fb2"></div>
<div class="fb3"></div>
<div class="fb4"></div>
JavaScript solution with Document.querySelectorAll() and Array.prototype.forEach():
var arr = [3,0,1,0,0];
var elements = [].slice.call(document.querySelectorAll('[class^=fb]'));
elements.forEach(function(div, idx){
if(arr.length >= idx) // check if the array length is grater/equal to the current index.
div.textContent = arr[idx];
});
<div class="fb0"></div>
<div class="fb1"></div>
<div class="fb2"></div>
<div class="fb3"></div>
<div class="fb4"></div>
You can use querySelectorAll to select the div's and than using forEach you can add the values to each div accordingly.
function update(){
let arr = [3,0,1,0,0];
let divs = document.querySelectorAll('[class^=fb]')
divs.forEach((e,i)=>{
e.innerHTML = arr[i]
})
}
<div class="fb0"></div>
<div class="fb1"></div>
<div class="fb2"></div>
<div class="fb3"></div>
<div class="fb4"></div>
<button onClick=update()>Click me to see output</button>

How to search for value in all descendant textNodes(Javascript)?

So basically I am making a Chrome extension which sorts the search results on Ebay by their popularity(number of times sold). To do this I need to find all li elements which have a descendant text node containing the text ...+ Sold where ... is a number.
Basically, search results on Ebay look like this:
<li class="s-item">
<div class="s-item__wrapper clearfix">
<div class="s-item__image-section">
<!-- other stuff -->
</div>
<div class="s-item__info clearfix">
<!-- other stuff -->
<div class="s-item__details clearfix">
<!-- other stuff -->
<div><span><span>62+ Sold</span></span></div>
</div>
</div>
</div>
</li>
In every li element I have to search for the text Sold and extract the number out of that text node to process it further. How can I do that?
You cannot do that only by using childNodes or children properties because they return only the children and not all descendants of the current node. So you will have to write your own function for that, something like:
function getDescendants(node, arr) {
var i;
arr = arr || [];
for (i = 0; i < node.childNodes.length; i++) {
arr.push(node.childNodes[i])
getDescendants(node.childNodes[i], arr);
}
return arr;
}
Using this function, you just simply iterate over all descendants and check if they are text nodes ( nodeType == 3 ) and after that search for the word Sold in them. Extracting the number is pretty easy after that.
Something like:
var searchValue = "Sold";
var descendants = getDescendants(listItem);
for(var j = 0; j < descendants.length; j++) {
if(descendants[j].nodeType == 3){
if(descendants[j].nodeValue.indexOf(searchValue) > -1){
var text = descendants[j].nodeValue.trim();
//"37+ Sold" for example
var soldNr = text.substring(0, text.indexOf(searchValue)-2);
//you process your number(soldNr) further
}
}
}
Use a selector string: select li.s-item span to select all spans which descend from an li with a class of s-item, check to see if the span's only child is a text node with "Sold" in it, and if so, do whatever you need to do with it.
If you're sure that any <li> will do, and not just those with a class of s-item, then use 'li span' instead:
document.querySelectorAll('li span').forEach(({ childNodes, textContent }) => {
if (childNodes.length !== 1 || childNodes[0].nodeType !== 3 || !textContent.includes('Sold')) return;
const count = textContent.match(/\d+/);
console.log('Processing span with sold number ' + count);
});
<ul>
<li class="s-item">
<div class="s-item__wrapper clearfix">
<div class="s-item__image-section">
<!-- other stuff -->
</div>
<div class="s-item__info clearfix">
<!-- other stuff -->
<div class="s-item__details clearfix">
<!-- other stuff -->
<div><span><span>62+ Sold</span></span>
</div>
</div>
</div>
</div>
</li>
<li class="s-item">
<div class="s-item__wrapper clearfix">
<div class="s-item__image-section">
<!-- other stuff -->
</div>
<div class="s-item__info clearfix">
<!-- other stuff -->
<div class="s-item__details clearfix">
<!-- other stuff -->
<div><span><span>333+ Sold</span></span>
</div>
</div>
</div>
</div>
</li>
</ul>

Categories

Resources