Looking for a javascript solution to reorder divs - javascript

I have some divs in the page that show different things of the same kind, for example offers, now offers have ending time, and also posted time, if the user wants to order by ending time, or posted time, they should be re ordered.
I'm looking for a javascript solution that could do that, any particular libraries under Ext JS , or JQuery would work
Here is how these divs look like
<div data-sortunit="1" data-sort1="40" data-sort2="156" data-sort3="1"
data-sort4="1317620220" class="item">
</div>
<div data-sortunit="2" data-sort1="30" data-sort2="116" data-sort3="5"
data-sort4="1317620220" class="item">
</div>
<div data-sortunit="3" data-sort1="10" data-sort2="157" data-sort3="2"
data-sort4="1317620220" class="item">
</div>
So I wanna be able to sort these divs based on data-sortN, N being an integer

Edit: OK, now that you've supplied some HTML, here's javascript code that will sort that specific HTML by the desired column number:
function sortByDataItem(containerID, dataNum) {
var values = [];
$("#" + containerID + " .item").each(function(index) {
var item = {};
item.index = index;
item.obj = this;
item.value = $(this).data("sort" + dataNum);
values.push(item);
});
values.sort(function(a, b) {return(b.value - a.value);});
var container = $("#" + containerID);
for (var i = 0; i < values.length; i++) {
var self = $(values[i].obj);
self.detach();
container.prepend(self);
}
return;
}
$("#sort").click(function() {
var sortValue = $("#sortColumn").val();
if (sortValue) {
sortValue = parseInt(sortValue, 10);
if (sortValue && sortValue > 0 && sortValue <= 3) {
sortByDataItem("container", sortValue);
return;
}
}
$("#msg").show(1).delay(5000).fadeOut('slow');
});
You can see it work here in a jsFiddle: http://jsfiddle.net/jfriend00/JG32X/
Since you've given us no HTML to go on, I've made my own HTML and shown you how you can use jQuery to sort:
HTML:
<button id="sort">Sort</button><br>
<div id="productList">
<div class="row"><div class="productName">Popcorn</div><div class="price">$5.00</div></div>
<div class="row"><div class="productName">Peanuts</div><div class="price">$4.00</div></div>
<div class="row"><div class="productName">Cookie</div><div class="price">$3.00</div></div>
<div class="row"><div class="productName">Beer</div><div class="price">$5.50</div></div>
<div class="row"><div class="productName">Soda</div><div class="price">$4.50</div></div>
</div>
Javascript (run after page is loaded):
$("#sort").click(function() {
var prices = [];
// find all prices
$("#productList .price").each(function(index) {
var str = $(this).text();
var item = {};
var matches = str.match(/\d+\.\d+/);
if (matches && matches.length > 0) {
// parse price and add it to the prices array
item.price = parseFloat(matches[0]);
item.row = $(this).closest(".row").get(0);
item.index = index;
prices.push(item);
}
});
// now the prices array has all the prices in it
// sort it using a custom sort function
prices.sort(function(a, b) {
return(a.price - b.price);
});
// now pull each row out and put it at the beginning
// starting from the end of the prices list
var productList = $("#productList");
for (var i = prices.length - 1; i >= 0; i--) {
var self = $(prices[i].row);
self.detach();
productList.prepend(self);
}
});
And, a jsFiddle that shows it in action: http://jsfiddle.net/jfriend00/vRdrA/.

I made a tiny jqueryPlugin out of jfriend00's answer:
(function($){
$.fn.sortChildrenByDataKey = function(key, desc){
    var i, els = this.children().sort(function(a, b) {return (desc?1:-1)*($(a).data(key) - $(b).data(key));});
    for (i = 0; i < els.length; i++) {
        this.prepend($(els[i]).detach());
    }
return this;
};
})(jQuery);
Your HTML:
<div id="myContainer">
<div data-myKey="4"> ... </div>
<div data-myKey="2"> ... </div>
...
</div>
Usage:
$('div#myContainer').sortChildrenByDataKey('myKey', true_or_false);
The children of the container can be any Elements. Its only important, that they are immediate children and have data-X key.
Thank you, jfriend00!!

Related

append method is not working in for loop

I have multiple json object and each object have multiple same, For example:
A->
- A1
-A1A
-A1A
- A2
-A2A
-A2A
- A3
-A3A
-A3A
I have tired to execute in below code but it's not working. Can you please suggest me what is the issue in my code?
subscriptionbarMyData = JSON.parse(window.localStorage.getItem('subscriptionBarJson'));
$('.total-month-cost-product-header-names').text('').addClass('hidden');
for (var key in subscriptionbarMyData) {
if (subscriptionbarMyData.hasOwnProperty(key)) {
var val = subscriptionbarMyData[key];
$('.total-month-cost-product-header')
.find('.total-month-cost-product-header-names')
.removeClass('hidden')
.addClass('show')
.text(val.Name + val.ProductPrice);
var addonvalue = subscriptionbarMyData[key]["Add-on"];
for (var keyval in addonvalue) {
if (addonvalue != undefined) {
var TotalOneCostProduct = $('.total-month-cost-product-items').text('');
for (var keyval in addonvalue) {
// var dataValues = addonvalue[keyval].Name;
$('.total-month-cost-product-header-names')
.text(addonvalue[keyval].Name)
.appendTo(TotalOneCostProduct);
}
}
}
}
}
<div class="summary-block">
<div class="total-month-cost-summary">
<div class="total-month-cost-product-header">
<div class="total-month-cost-product-header-names"></div>
<div class="total-month-cost-product-header-price"></div>
</div>
<div class="total-month-cost-product-items">
<div class="total-month-cost-product-item-names"></div>
<div class="total-month-cost-product-item-price"></div>
</div>
</div>
</div>

How to show nearest div id for a given input number?

Let's say I have the following input field:
<input id="inputField" type="number" value="">
and some divs such as:
<div id="1000"></div>
<div id="1200"></div>
<div id="1500"></div>
<div id="1900"></div>
...
When the user enters a number in the input field, I want my code to go to the nearest div id to that number.
e.g: If user enters 1300 then show div with id = "1200".
What's the most efficient way to implement that in javascript considering there will be a large number of divs?
Right now I'm doing:
<script>
function myFunction()
{
var x = document.getElementById("inputField").value;
if(x >= 1750 && x <= 1900)
{
window.location.hash = '#1800';
}
}
</script>
One way is to wrap all your divs with number ids in another div if you can (and give it some id, say 'numbers'); this allows you to find all the divs in your javascript file.
Javascript:
// Get all the divs with numbers, if they are children of div, id="numbers"
let children = document.getElementById('numbers').children;
let array = [];
for (i = 0; i < children.length; i++) {
// Append the integer of the id of every child to an array
array.push(parseInt(children[i].id));
}
// However you are getting your input number goes here
let number = 1300 // Replace
currentNumber = array[0]
for (const value of array){
if (Math.abs(number - value) < Math.abs(number - currentNumber)){
currentNumber = value;
}
}
// You say you want your code to go to the nearest div,
// I don't know what you mean by go to, but here is the div of the closest number
let target = document.getElementById(currentNumber.toString());
Let me know if there's more I can add to help.
Demo
function closestNum() {
let children = document.getElementById('numbers').children;
let array = [];
for (i = 0; i < children.length; i++) {
array.push(parseInt(children[i].id));
}
let number = document.getElementById('inputnum').value;
currentNumber = array[0]
for (const value of array) {
if (Math.abs(number - value) < Math.abs(number - currentNumber)) {
currentNumber = value;
}
}
let target = document.getElementById(currentNumber.toString());
document.getElementById('target').innerHTML = target.innerHTML;
}
<div id="numbers">
<div id="1000">1000</div>
<div id="2000">2000</div>
<div id="3000">3000</div>
<div id="4000">4000</div>
<div id="5000">5000</div>
</div>
<br />
<input type="text" id="inputnum" placeholder="Input Number" onchange="closestNum()" />
<br />
<br /> Target:
<div id="target"></div>
With some optimization this shall be ok-
var element;
document.addEventListener("change",
function(evt){
if(element && element.classList){
element.classList.remove("selected", false);
element.classList.add("unselected", true);
}
var listOfDivs =
document.querySelectorAll(".unselected");
var val = evt.target.value;
var leastAbs=listOfDivs[0].id;
for(let anIndex=0, len=listOfDivs.length;anIndex<len;anIndex++){
if(Math.abs(listOfDivs[anIndex].id-val)<leastAbs){
leastAbs = Math.abs(listOfDivs[anIndex].id-val);
element = listOfDivs[anIndex];
}
}
element.classList.remove("unselected");
element.classList.add("selected");
});
.selected{
background-color:red;
}
.unselected{
background-color:yellow;
}
.unselected, .selected{
width:100%;
height:50px;
}
<input id="inputField" type="number" value="">
<div id="1000" class='unselected'>1</div>
<div id="1200" class='unselected'>2</div>
<div id="1500" class='unselected'>3</div>
<div id="1900" class='unselected'>4</div>
This may work for you. Loops through each div and compared it to your inputted ID. Tracks closest one, hides all divs, then displays the closest.
document.getElementById("inputField").addEventListener("change", function(){
var divs = document.getElementsByTagName("div");
var closestDiv = -1;
var inputId = document.getElementById("inputField").value;
for(var i=0; i<divs.length; i++)
{
if(Math.abs(inputId - closestDiv) > Math.abs(inputId - divs[i].id) || closestDiv == -1)
{
closestDiv = divs[i].id;
for (var x = 0; x < divs.length; x++) {
divs[x].style.display = 'none';
}
divs[i].style.display = "block";
}
}
});
See it Live: jsfiddle.net

Get the implicit lang attribute of an HTML element

Suppose you have an HTML page that contains sections in different languages, like this:
<html lang=en>
<div lang="th">
<p id="test1">ไทย</p>
</div>
<p id="test2">Implicitly English</p>
<div lang="en-CA">
<p id="test3">As Canadian as possible under the circumstances</p>
</div>
<p lang="en-AU"id="test4">Explictly Aussie</p>
</html>
Is there a direct way to discover which particular language code applies to a given HTML element? Something like:
// pseudo-code
var lang = myElement.getLang()
Here's what appears to be a very roundabout solution:
function getLang(element) {
var lang = element.getAttribute("lang")
if (!lang) {
var elements
, languages
, language
, ii
, selector
// Find all elements with an explicit lang attribute
elements = [].slice.call(document.querySelectorAll("*[lang]"))
// Determine which languages are present
languages = []
for (ii in elements) {
lang = elements[ii].getAttribute("lang")
if (languages.indexOf(lang) < 0) {
languages.push(lang)
}
}
lang = "" // reset
for (ii in languages) {
language = languages[ii]
selector = ":lang(" + language + ")"
elements = [].slice.call(document.querySelectorAll(selector))
if (elements.indexOf(element) > -1) {
if (lang.length < language.length) {
lang = language
}
}
}
}
return lang
}
Is there a more obvious way?
jsFiddle
I updated your fiddle with the following code, which you can run in this snippet. This simplifies it greatly.
function getLang(elem) {
var lang = "";
if (elem) {
var elements = [];
var queryResult = document.querySelectorAll("[lang]");
try {
//Wrapping in a try catch block to handle unsupported browsers.
elements = [].slice.call(queryResult);
} catch (error) {
for (var i = 0, len = queryResult.length; i < len; i++) {
elements.push(queryResult[i]);
}
}
if (elements.length > 0) {
//Find in the NodeList where the element is either itself or the first parent with lang attribute of the given element.
var matches = elements.filter(function(e) {
return e === elem || e.contains(elem);
}); //ES2015 -> elements.filter(e => e === elem || e.contains(elem));
var match = matches.length > 0 ? matches[matches.length - 1] : matches[0];
lang = match.lang ? match.lang : lang;
}
}
return lang;
}
var result = getLang(document.querySelector("#test1")) + " ";
result += getLang(document.querySelector("#test2")) + " ";
result += getLang(document.querySelector("#test3")) + " ";
result += getLang(document.querySelector("#test4"));
alert(result);
<body lang=en>
<div lang="th">
<p id="test1">ไทย</p>
</div>
<p id="test2">Implicitly English</p>
<div lang="en-CA">
<p id="test3">As Canadian as possible under the circumstances</p>
</div>
<p lang="en-AU" id="test4">Explictly Aussie</p>
</body>

Unable to slice strings retrieved from div's

I'm having trouble slicing text I retrieved from a div with javascript/jquery. I thought you could slice every string and that the .text() function always returned a string so I fail to see the problem. Any help will be greatly appreciated!
Fiddle
Html:
<body>
<div class="vaknaam">Div 1 :<span class="totaal">55%</span>
</div>
<div class="vaknaam">Div 2 :<span class="totaal">60%</span>
</div>
<div class="vaknaam">Div 3 :<span class="totaal">64%</span>
</div>
<div class="vaknaam">Div 4 :<span class="totaal">76%</span>
</div>
<div class="vaknaam">Div 5 :<span class="totaal">63%</span>
</div>
</body>
Javascript:
$(function () {
var divs = {};
var tempString, vakken = {};
$('.vaknaam').each(function (key, value) {
tempString = $(value).contents().filter(function () {
return this.nodeType == 3;
}).text();
tempString = tempString.slice(0, - 2);
vakken[tempString] = $(value).children('span').text();
});
for (var property in vakken) {
$('body').append("<p>" + property + "</p>");
}
});
You have several errors.
You need to declare an initialise the var vakken.
The slice method does not modify the string so you should assign what returns to something.
property var is just an index so you need to ask for vakken[property]
Your code should look like this:
$(function () {
var divs = {};
var tempString, vakken = {}; //1
$('.vaknaam').each(function (key, value) {
tempString = $(value).contents().filter(function () {
return this.nodeType == 3;
}).text();
tempString = tempString.slice(0, -4); //2
vakken[tempString] = $(value).children('span').text();
});
for (var property in vakken) {
$('body').append("<p>" + property + "</p>"); //3
}
});
Check out this codepen.
slice doesn't modify the initial string, which is immutable. Try:
tempString = tempString.slice(0, - 2);

Count all numbers inside Parent div, and then sort them on Totals

I want to calculate the total per "row-counts" of all "counts" inside, and then sort "row" based on the "row-totals". But the totals add up all numbers with class="count" instead of 'for each' only those within it's parent "row-counts".
<div id="container">
<div class="row">
<div class="row-counts">
<span class="count">12</span>
<span class="count">4</span>
<span class="count">5</span>
<span class="count">7</span>
</div>
<div class="row-totals">
</div>
</div>
<div class="row">
<div class="row-counts">
<span class="count">4</span>
<span class="count">66</span>
<span class="count">0</span>
<span class="count">12</span>
</div>
<div class="row-totals">
</div>
</div>
<div class="row">
<div class="row-counts">
<span class="count">7</span>
<span class="count">99</span>
<span class="count">42</span>
<span class="count">17</span>
</div>
<div class="row-totals">
</div>
</div>
</div>
<script>
// to calculate sum of all numbers in .row-counts
$('.row-counts').each(function(){
var sum = 0;
var select = $(this).find('.count');
select.each(function()
{
sum += parseFloat($(this).text());
});
$('.row-totals').html(sum);
});
// to sort on .row-totals
$(".row-totals").orderBy(function() {return +$(this).text();}).appendTo("#container");
jQuery.fn.orderBy = function(keySelector)
{
return this.sort(function(a,b)
{
a = keySelector.apply(a);
b = keySelector.apply(b);
if (a > b)
return 1;
if (a < b)
return -1;
return 0;
});
};
</script>
Sorting plugin is from this topic: Sorting divs by number inside div tag and jQuery
Here you go. Code commented with some pointers. Hope this helps.
http://jsfiddle.net/N5Sd2/
// to calculate sum of all numbers in .row-counts
$('.row').each(function(index,RowElement){ // For each row
var thisRowTotal = $(RowElement).find('.row-totals'); // set output div in variable
var thisRowCounts = $(RowElement).find('.row-counts'); // set row count parent div in variable
var sum = 0; // create sum var
thisRowCounts.each(function(i,RowCountParent){ // for each row count parent
var select = $(RowCountParent).find('.count'); // find counts
select.each(function(i,e){ // for each count found
sum = sum + parseInt($(e).html()); // convert into integer and add to sum
}); // when finished
thisRowTotal.html(sum); // output sum to output div
});
});
// to sort on .row-totals
jQuery.fn.orderBy = function(keySelector) // MAKE SURE YOU INIT THE PLUGIN...
{
return this.sort(function(a,b)
{
a = keySelector.apply(a);
b = keySelector.apply(b);
if (a > b)
return 1;
if (a < b)
return -1;
return 0;
});
};
// ....BEFORE YOU CALL IT IN YOUR CODE! This line moved UNDER the plugin.
$(".row-totals").orderBy(function() {return +$(this).text();}).appendTo("#container");
I didn't test it, but I think you need one more level in your iteration. This should do the trick:
$('.row').each(function() {
var total = $(this).find('.row-totals');
var sum = 0;
$(this).find('.row-counts').each(function(){
var select = $(this).find('.count');
select.each(function() {
sum += parseFloat($(this).text());
});
total.html(sum);
});
});
And then use your sort plugin as usual.

Categories

Resources