JQuery Sort Divs by child divs - javascript

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/

Related

Add an existing div element with classes (along with its underlying elements) to a div

I need to have a function that would add an existing div with a class (along with its underlying elements) to a particular div using for loop. It looks like this:
<div class="left-col">
<div class="list-row">
<div class="list-row2">
<span>Hello</span>
</div>
</div>
</div>
I need to loop through a function that will produce or duplicate "list-row" twice.
$(function() {
var leftcol = document.getElementsByClassName('left-col');
for (var i = 0; i < 2; i++) {
var listrow = document.querySelector('.list-row');
leftcol.appendChild(listrow[i]);
}
})
It should look like this:
<div class="left-col">
<div class="list-row">
<div class="list-row2">
<span>Hello</span>
</div>
</div>
<div class="list-row">
<div class="list-row2">
<span>Hello</span>
</div>
</div>
<div class="list-row">
<div class="list-row2">
<span>Hello</span>
</div>
</div>
</div>
You can try the following way:
$(function() {
var leftcol = document.querySelector('.left-col');
for (let i = 0; i < 2; i++) {
var listrow = document.querySelector('.list-row').cloneNode();
listrow.textContent = i + 1 + listrow.textContent;
leftcol.appendChild(listrow);
}
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="left-col">
<div class="list-row">0</div>
</div>
You could use cloneNode and set the deep property to true. This will clone the node and all of its descendants.
For example:
function cloneNode(copies = 1) {
for (let i = 0; i < copies; i++) {
let leftcol = document.getElementsByClassName('left-col')[0];
let nodeToClone = document.querySelector(".list-row");
let clonedNode = nodeToClone.cloneNode(true);
leftcol.appendChild(clonedNode);
}
}
clone.addEventListener("click", function() {
cloneNode();
});
<button id="clone" type="button">Clone Node</button>
<div class="left-col">
<div class="list-row">Test</div>
</div>
If you wanted to insert more than one copy, you could pass a different value to the cloneNode function.
You can use jQuery's .clone() method to copy the entire content of an element to another element. The boolean argument passed to the clone function determines whether the events associated with the cloned element has to be copied or not. true indicates all the events associated with that div has to be copied.
$(function() {
$('.list-row').each(function(){
$(".left-col").append($(this).clone(true));
});
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.0/jquery.min.js"></script>
<div class="left-col">
<div class="list-row"><h1>This is original row</h1></div>
</div>
$(function() {
var leftcol = document.getElementsByClassName('left-col');
var listrow = document.querySelector('.list-row');
for (var i = 0; i < 2; i++) {
leftcol.appendChild(listrow.clone(true));
}
})

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>

get multiple element li with javascript

What I need to get all value of multiple li from the HTML code.
<div class="row">
<div style="margin-left:11px">
<strong>Detail Product</strong>
</div>
<div class="col-sm-12">
<ul class="item-highlights">
<li>4G LTE</li>
<li>Dual Sim</li>
<li>RAM 1GB</li>
</ul>
</div>
<div class="col-sm-12">
<ul class="item-highlights">
<li>ROM 8GB</li>
<li>Screen 5.5</li>
<li>Warranty 1 Year</li>
</ul>
</div>
This how i get with javascript:
var test = document.getElementById('block-system-main').getElementsByClassName('item-highlights item-highlights')[0].innerHTML;
and i get the answer:
<li>4G LTE</li><li>Dual Sim</li><li>RAM 1GB</li>
Heres an easy to understand answer.
var items = document.querySelectorAll( ".item-highlights li");
var values = [];
for( var n = 0; n < items.length; n++)
values.push( items[n].innerHTML);
If you know css then its simple to change the call to "querySelectorAll" as it is only comparing things through the same way css does, So you can change it however you like.
Expanding on #Tushar comment:
var test = '';
[].forEach.call( document.querySelectorAll('#block-system-main .item-highlights'), function(item) { return test += item.innerText; })
Check demo - Fiddle.
You should be able to select every li using querySelectorAll and then map those values. It would look like this:
var listItems = Array.prototype.slice.call(document.querySelectorAll('li'));
var vals = listItems.map(function (item) {
return item.innerHTML;
});
Example:
http://jsbin.com/zumewidoyo/edit?html,js,console
If you want to select every li element you can do something like this:
Live Preview
HTML
<div class="row">
<div style="margin-left:11px">
<strong>Detail Product</strong>
</div>
<div class="col-sm-12">
<ul class="item-highlights">
<li>4G LTE</li>
<li>Dual Sim</li>
<li>RAM 1GB</li>
</ul>
</div>
<div class="col-sm-12">
<ul class="item-highlights">
<li>ROM 8GB</li>
<li>Screen 5.5</li>
<li>Warranty 1 Year</li>
</ul>
</div>
JavaScript
//store the list elements
var lists = document.getElementsByTagName('li');
//array to hold the li elements
var liElements = [];
//loop through the lists
for (var i = 0; i < lists.length; i++) {
//add the li element values to the array
liElements.push(lists[i].innerHTML);
}
//show the results
alert(liElements.join("\n"));
The function getElementsByClassName return an array. Just iterate over it instead of using the "[0]" to get only the first element.
function getValue() {
var test = document.getElementById('block-system-main').getElementsByClassName('item-highlights');
var array = [];
for (var i = 0; i < test.length; i++) {
var liList = test[i].getElementsByTagName('li');
for (var j = 0; j < liList.length; j++)
array.push(liList[j].innerHTML);
}
return array;
}
alert(getValue());
<div id="block-system-main">
<div class="row">
<div style="margin-left:11px">
<strong>Detail Product</strong>
</div>
<div class="col-sm-12">
<ul class="item-highlights">
<li>4G LTE</li>
<li>Dual Sim</li>
<li>RAM 1GB</li>
</ul>
</div>
<div class="col-sm-12">
<ul class="item-highlights">
<li>ROM 8GB</li>
<li>Screen 5.5</li>
<li>Warranty 1 Year</li>
</ul>
</div>
</div>
</div>

jquery filtered elements moved between divs

I'm bulding small filtering feature for items listed in div elements. These div elements are in a slider placed next to each other.
So each column contains a number of items. The filtering is working but i can't find a way to group the filtered items one under another so they would be in a first colum, not in their oryginal column:
<input id="filter" name="filter" size="40"/>
<div class="filtered">
<div class="archive-col-1 column">
<div class="name"><div class="element">Alchemy</div></div>
<div class="name"><div class="element">Balboa</div></div>
<div class="name"><div class="element">Nebula</div></div>
<div class="name"><div class="element">Radio</div></div>
</div>
<div class="archive-col-2 column">
<div class="name"><div class="element">Mathematics</div></div>
<div class="name"><div class="element">Disco</div></div>
<div class="name"><div class="element">Antwon</div></div>
<div class="name"><div class="element">Barracuda</div></div>
</div>
<div class="archive-col-3 column">
<div class="name"><div class="element">English</div></div>
<div class="name"><div class="element">France</div></div>
<div class="name"><div class="element">Nairobi</div></div>
<div class="name"><div class="element">Crazy</div></div>
</div>
</div>
function filter(element) {
$("#filter").keyup(function () {
var filter = $(this).val();
count = 0;
$(".column .element").each(function () {
var parent = $(this).parent();
var length = $(this).text().length > 0;
if (length && $(this).text().search(new RegExp(filter, "i")) < 0) {
parent.hide();
} else {
parent.show();
//appendTo.closest('.colums');
count++;
}
});
});
}
$('input').on('keyup change', function () {
filter(this);
});
example: http://jsfiddle.net/pw7k2/
In my another example filtering works fine but I don't know how to limit rows and move other filtered items to the next column, now they go to first column only:
http://jsfiddle.net/yQD7X/
Did anyone have similar problem?
http://jsfiddle.net/pw7k2/2/
function dispatchElements() {
var $elements = $('.column .element:visible').remove();
var $column = $('.column:first');
$elements.each(function(index, value) {
var height = $column.height();
var $childrens = $column.children(':visible');
var childrenHeight = 0;
$childrens.each(function(){
childrenHeight += $(this).outerHeight();
});
childrenHeight += childrenHeight/$childrens.length;
if (childrenHeight > height) {
$column = $column.next();
}
$(this).appendTo($column);
});
}
This method removes all visible elements and dispatch them after checking if there's available space in the current column, if not it takes the next one.

Categories