Sort divs by multiple data attributes - javascript

How can I sort by both of the data attributes? First I need to sort by discount and then sort by weight.
<div id="list">
<div class="row" data-weight="1" data-discount=0>banana</div>
<div class="row" data-weight="3" data-discount=30>apple</div>
<div class="row" data-weight="4" data-discount=0>avocado</div>
<div class="row" data-weight="8" data-discount=15>milk</div>
</div>
function sortOrder(){
divList.sort(function(a, b){
return $(b).data("order")-$(a).data("order")
});
$(".list").html(divList);
}

Your current sort() logic shows how to do this for a single attribute. For multiple attributes you simply need to amend the logic to cater for cases where the values are the same, which can be seen below.
Note that this logic can be made less verbose, but I left it this way to make the flow more obvious.
var $divList = $('#list .row');
function sortOrder() {
$divList.sort(function(a, b) {
var $a = $(a), $b = $(b);
if ($a.data('discount') < $b.data('discount')) {
return 1;
} else if ($a.data('discount') > $b.data('discount')) {
return -1;
}
if ($a.data('weight') < $b.data('weight')) {
return 1;
} else if ($a.data('weight') > $b.data('weight')) {
return -1;
}
return 0;
});
$("#list").append($divList);
}
sortOrder();
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="list">
<div class="row" data-weight="1" data-discount=0>banana</div>
<div class="row" data-weight="3" data-discount=30>apple</div>
<div class="row" data-weight="4" data-discount=0>avocado</div>
<div class="row" data-weight="8" data-discount=15>milk</div>
</div>

Related

How can I sort divs with javascript

I would like to sort a few divs in ascending order based on their data-id. How can I do that?
<div class="container" data-id="1000">
<div id="H1"></div>
<div id="sub">sub 1</div>
<div id="sub">sub 2</div>
</div>
<div class="container" data-id="3000">
<div id="H1"></div>
<div id="sub"></div>
<div id="sub"></div>
</div>
<div class="container" data-id="2000">
<div id="H1"></div>
<div id="sub"></div>
<div id="sub"></div>
</div>
I've found the solution to my problem a while ago:
function sortOut() {
// get the classname chapcontainer
var classname = document.getElementsByClassName('container');
// create a variable and put the classes it into an array.
var divs = [];
for (var i = 0; i < classname.length; ++i) {
divs.push(classname[i]);
}
// Sort the divs based on data-id.
divs.sort(function(a, b) {
return +a.getAttribute("data-id") - +b.getAttribute("data-id");
});
};
divs.sort does the trick. More info about this function can be found here:
https://www.w3schools.com/jsref/jsref_sort.asp

How to detect number of elements has text start with special word using jquery?

I have a tag like below:
<section id="sec">
<div id="item1">item1</div>
<div id="item2">item2</div>
<div id="item3">item3</div>
<div id="abcitem1">abcitem1</div>
</section>
I want to check how many div tags contextText start with item. May I know is there any easier way that writes for condition and count them one by one(like Jquery)?
Use .filter() to filtering selected elements and use regex in .match() to check existence of item in element text.
var count = $("#sec div").filter(function(){
return $(this).text().match(/^item/);
}).length;
console.log(count);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<section id="sec">
<div id="item1">item1</div>
<div id="item2">item2</div>
<div id="item3">item3</div>
<div id="abcitem1">abcitem1</div>
</section>
var res=0;
$( "#sec div" ).each(function( index ) {
var str= $(this).text() ;
if(str.startsWith("item")==true){
res++;
}
});
console.log(res); //returns 3
You could use reduce function to get the occurrence of elements which start with 'item'.
This is a native javascript solution, which uses startsWith, so you do not have to mess around with regular expressions.
var childDivs = document.getElementById('sec')
.getElementsByTagName('div');
var counter = Array.from(childDivs)
.reduce((accumulator, currentValue) => {
if (currentValue.innerHTML.startsWith('item')) {
return accumulator = accumulator + 1;
}
return accumulator;
}, 0);
console.log( counter );
<section id="sec">
<div id="item1">item1</div>
<div id="item2">item2</div>
<div id="item3">item3</div>
<div id="abcitem1">abcitem1</div>
</section>
Without any jQuery or regex
var nodes = document.querySelectorAll('#sec div')
var count = 0
nodes.forEach(node => count += node.innerText.startsWith('item'))
console.log(count)
<section id="sec">
<div id="item1">item1</div>
<div id="item2">item2</div>
<div id="item3">item3</div>
<div id="abcitem1">abcitem1</div>
</section>
it's possible to add booleans to a number, true means 1 and false means 0
Here is a pure JS way to count it.
function checkItemsCount(section) {
if (!section) return 0;
const sec = document.querySelector(section);
const items = sec.querySelectorAll('div');
let count = 0;
for (let i = 0; i < items.length; i++) {
if (/^item/.test(items[i].innerText)) count++;
}
return count;
}
console.log(checkItemsCount('#sec'));
<section id="sec">
<div id="item1">item1</div>
<div id="item2">item2</div>
<div id="item3">item3</div>
<div id="abcitem1">abcitem1</div>
</section>

Find first instance of specific value and add ID, repeated

Given a series of div's with known values is it possible to create a filter or array that finds the first instance of the values and adds an ID over multiple items? Here's the basic structure:
<div class="boxes">
<div class="box"><time>2017</time></div>
<div class="box"><time>2016</time></div>
<div class="box"><time>2015</time></div>
<div class="box"><time>2014</time></div>
<div class="box"><time>2014</time></div>
<div class="box"><time>2014</time></div>
<div class="box"><time>2013</time></div>
</div>
And here's the snippet I'm using to find one of the values:
var elems = $('.box').filter(function(){
return this.textContent.trim() === "2014"
}).first().attr('id', 'one');
I'm not sure the best way to go about looking for additional instances?
For example, it feels like there's a better way than simply repeating the argument. The novice in me admittedly does not know what this type of function would be called.
var elems = $('.box').filter(function(){
return this.textContent.trim() === "2014"
}).first().attr('id', 'one');
var elems = $('.box').filter(function(){
return this.textContent.trim() === "2017"
}).first().attr('id', 'one');
It would be a bonus to not have to add the specific value, i.e. 2017 (<time id="one">2017</time>), 2016 (<time id="two">2016</time>) but I'm not even sure if that's realistic.
Working Fiddle: https://jsfiddle.net/heykenneth/gn4gmvt0/1/.
You can do this by wrapping up parameters of the code you've already written:
markFirstYear("2014", "one");
markFirstYear("2015", "two");
markFirstYear("2016", "three");
markFirstYear("2017", "four");
// ... etc
function markFirstYear(year, id) {
var elems = $('.box').filter(function(){
return this.textContent.trim() === year
}).first().attr('id', id);
}
#one {color:red;}
#two {color:blue;}
#three {color:green;}
#four {color:purple;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="boxes">
<div class="box"><time>2017</time></div>
<div class="box"><time>2016</time></div>
<div class="box"><time>2015</time></div>
<div class="box"><time>2014</time></div>
<div class="box"><time>2014</time></div>
<div class="box"><time>2014</time></div>
<div class="box"><time>2013</time></div>
</div>
First create array of all values you have, then just get unique values from that array and finally iterate through unique array.
var myArr = new Array();
$('.box time').each(function(){
myArr.push($(this).text());
});
var unique = myArr.filter(function(item, index, array) {
return index == myArr.indexOf(item);
});
for (var i = 0; i <= unique.length; i++) {
var elems = $('.box').filter(function() {
return this.textContent.trim() === unique[i];
}).first().attr('class', 'one');
}
.one {color:red;}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="boxes">
<div class="box"><time>2017</time></div>
<div class="box"><time>2016</time></div>
<div class="box"><time>2015</time></div>
<div class="box"><time>2014</time></div>
<div class="box"><time>2014</time></div>
<div class="box"><time>2014</time></div>
<div class="box"><time>2013</time></div>
</div>

Toggle a class on and off between two elements

I have this html:
<div class="container">
<div id="element-1" class="element-show"></div>
<div id="element-2"></div>
</div>
I want class element-show to hide from element-1 and show in element-2 and vice versa; called from one function in jQuery.
Any way I can do this properly?
will something like that be OK?
$("button").on("click", function(e){
$('.container').children("div").toggleClass("element-show");
})
.element-show{
color:red;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div id="element-1" class="element-show">x</div>
<div id="element-2">y</div>
</div>
<button>Toggle class</button>
You can achieve that by doing this:
function getClass() {
var children_container = document.getElementsByClassName("container")[0].children;
for (var i = 0; i < children_container.length; i++) {
if ($(children_container[i]).hasClass('element-show')) {
$(children_container[i]).removeClass();
if (i == "0") {
$(children_container[1]).addClass("element-show");
break;
} else if (i == "1") {
$(children_container[0]).addClass("element-show");
break;
}
}
};
};
getClass();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div id="element-1" class="element-show"></div>
<div id="element-2"></div>
</div>
If you have more than 2 elements and you want to add the class on rest of them and remove it from the element which already has that class, then you can achieve that by doing this (this function will also work for the case you mentioned too):
function getClass() {
var children_container = document.getElementsByClassName("container")[0].children;
var class_elem;
for (var i = 0; i < children_container.length; i++) {
if ($(children_container[i]).hasClass('element-show')) {
class_elem = i;
$(children_container[i]).removeClass();
i = 0;
}
if (class_elem != undefined) {
if (i != class_elem) {
$(children_container[i]).addClass('element-show');
}
};
};
};
getClass();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div class="container">
<div id="element-0"></div>
<div id="element-1" class="element-show"></div>
<div id="element-2"></div>
<div id="element-3"></div>
<div id="element-4"></div>
</div>

JQuery Sort Divs by child divs

I have the following list of divs and I'd like to be able to sort them using Javascript / JQuery.
<div class="item">
<div class="genre">Classical</div>
<div class="name">Alpha</div>
<div class="location">London</div>
</div>
<div class="item">
<div class="genre">Blues</div>
<div class="name">Bravo</div>
<div class="location">New York</div>
</div>
<div class="item">
<div class="genre">Pop</div>
<div class="name">Charlie</div>
<div class="location">Paris</div>
</div>
<div class="buttons">
Sort by Genre
Sort by Name
Sort by Location
</div>
I'd like to be able to sort the items by their Genre/Name/Location alphabetically.
Example: If Sort by Genre was clicked, it would sort the items in 0-9 A-Z by Genre.
If any of you have any tips it would greatly be appreciated.
Cheers :)
You have to make a little change to html like following:
<div id="container">
<div class="item">
<div class="genre">Classical</div>
<div class="name">Alpha</div>
<div class="location">London</div>
</div>
<div class="item">
<div class="genre">Blues</div>
<div class="name">Bravo</div>
<div class="location">New York</div>
</div>
<div class="item">
<div class="genre">Pop</div>
<div class="name">Charlie</div>
<div class="location">Paris</div>
</div>
</div>
<div class="buttons">
Sort by Genre
Sort by Name
Sort by Location
</div>
jQuery
function sorting(tag) {
var items = $('div.item').sort(function(a, b) {
var txt1 = $.trim($('div.' + tag, a).text()),
txt2 = $.trim($('div.' + tag, b).text());
if (txt1 > txt2) return 1;
else return -1;
});
return items;
}
$('.buttons a').on('click', function(e) {
e.preventDefault();
$('div#container').html(sorting(this.id));
});
Working Sample
Ok, this would be my pure JS solution.
First, we should wrap your <div>s into a larger container.
<div id = "wrapper">
<div id = "item">...</div>
<div id = "item">...</div>
<div id = "item">...</div>
</div>
Now, let's define a constant - which property do you want to sort it by? (this will probably be a function parameter later in your code).
var propName = "genre";
Let's get all the <div>s and put them in an array.
var items = document.getElementsByClassName("item");
var itemsArray = new Array();
Let us sort them lexicographically according to the text of the selected property.
for (var i = 0; i < items.length; i++)
itemsArray.push(items[i]);
itemsArray.sort(function(a, b) {
var aProp = a.getElementsByClassName(propName)[0].firstChild.nodeValue;
var bProp = b.getElementsByClassName(propName)[0] .firstChild.nodeValue;
if (aProp < bProp)
return -1;
else if (aProp > bProp)
return 1;
else
return 0;
});
Let us construct a document fragment consisting of the sorted <div>s.
var fragment = document.createDocumentFragment();
for (var i = 0; i < itemsArray.length; i++)
fragment.appendChild(itemsArray[i].clone());
Finally, let us clear the contents of the <div id = "wrapper"> and replace it with the document fragment.
document.getElementById('wrapper').innerHTML = '';
document.getElementById('wrapper').appendChild(fragment);
Also, note that document.getElementsByClassName does not work in IE<9, but I was now really lazy to cope with that issue.
A fiddle: http://jsfiddle.net/nNXr4/
Check this beast:
function sortByCreatedOnAsc(a,b){
return $(a).find('.created_on').text() > $(b).find('.created_on').text();
}
function sortByCreatedOnDesc(a,b){
return $(a).find('.created_on').text() < $(b).find('.created_on').text();
}
function reorderEl(el){
var container = $('#tasks');
container.html('');
el.each(function(){
$(this).appendTo(container);
});
}
$('#created_on').click(function(){
if($(this).hasClass("asc")){
reorderEl($('.task').sort(sortByCreatedOnDesc));
$(this).removeClass("asc");
$(this).addClass("desc");
} else {
reorderEl($('.task').sort(sortByCreatedOnAsc));
$(this).removeClass("desc");
$(this).addClass("asc");
}
return false;
});
jsfiddle: http://jsfiddle.net/jKJc3/116/

Categories