Swap "ul li" dynamically - javascript

I have my ul : li list with a span named as badge which contains the total number of unread messages. So i want to shuffle all the li items with the highest number on top of the list and lowest or none to the last. I tried many solutions but still can`t get it. Another point is the count gets update live so the list should also shuffle live. Here is the code that i tried till now.
My HTML Code
<li>
<span class="badge" style="display:none" id="61_T">0</span>
</li>
<li>
<span class="badge" style="display:none" id="62_T">5</span>
</li>
<li>
<span class="badge" style="display:none" id="63_T">10</span>
</li>
<li>
<span class="badge" style="display:none" id="64_T">0</span>
</li>
Here is my JS Code
var prev_index = 0;
var curr_index = 0;
var curr_val = 0;
var prev_val = 0;
var lists = $('#items li');
var msg_count = [];
$('#items li').each(function(){
var current_index = $(this).index();
var count = $(this).find('.badge').text();
msg_count.push([current_index,count]);
});
updateli();
function updateli(){
$.each(msg_count,function(key,value){
var str = value.join('-');
var sep = str.split('-');
curr_index = sep[0];
curr_val = parseInt(sep[1]);
if(curr_val > prev_val){
$("#items li:eq("+curr_index+")").siblings().eq(curr_index).after(lists.siblings(':eq('+prev_index+')'));
}
prev_index = curr_index;
prev_val = curr_val;
});
}
What i did here is created an array with li index and unread count number. After than looped the array and used jQuery function to swap the elements but nothing seems to work. Any help will really appreciated. Thanks in advance.

This sorts the list without using JQuery
function sortItems(containerSelector, itemSelector, countSelector, asc) {
let container = document.querySelector(containerSelector);
let items = [].slice.call(container.querySelectorAll(itemSelector));
items.sort(function(currItem, nextItem) {
var currCountElement = currItem.querySelector(countSelector);
var nextCountElement = nextItem.querySelector(countSelector);
if(!currCountElement) return 1;
if(!nextCountElement) return -1;
var currCount = parseInt(currCountElement.textContent || -1);
var nextCount = parseInt(nextCountElement.textContent || -1);
var order = currCount - nextCount;
return asc?-order:order;
});
items.forEach(function(item) { container.appendChild(item)});
}
// demo code
[].slice.call(document.querySelectorAll('.sortButton')).forEach(function(button) {
button.addEventListener('click', function(e) { sortItems('.items', 'li', '.badge', this.classList.contains('-desc')) });
});
<ul class="items">
<li>
2
<span class="badge" style="display:none" id="61_T">2</span>
</li>
<li>
5
<span class="badge" style="display:none" id="62_T">5</span>
</li>
<li>
10
<span class="badge" style="display:none" id="63_T">10</span>
</li>
<li>
1
<span class="badge" style="display:none" id="63_T">1</span>
</li>
<li>
0
<span class="badge" style="display:none" id="64_T">0</span>
</li>
<li>
none
<span class="badge" style="display:none" id="64_T"></span>
</li>
<li>
no badge
</li>
</ul>
<button class="sortButton">asc</button>
<button class="sortButton -desc">desc</button>
Edit: made it a method

try the code below please.jquery return a array-like object so you can sort elements by sort(..) method,and then replace all the li.
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li>
<span class="badge" id="61_T">0</span>
</li>
<li>
<span class="badge" id="62_T">5</span>
</li>
<li>
<span class="badge" id="63_T">10</span>
</li>
<li>
<span class="badge" id="64_T">0</span>
</li>
</ul>
<script>
var badges = $('.badge').parent().sort(function (a, b) {
return parseInt($(b).find('span').text()) - parseInt($(a).find('span').text());
});
badges.closest('ul').empty().append(badges);
</script>

Related

how to get specific element inside <li> element when clicked

I have this code that will console.log the innerHTML of the list element that is clicked, it works perfectly
But I wanted to only console.log the innerHTML of the span element with class "x" that is inside the list
how can I do this?
function myfunction() {
let items = document.querySelectorAll("#ol li"),
array = [];
for (var i = 0; i < items.length; i++) {
array.push(items[i].innerHTML);
}
for (var i = 0; i < items.length; i++) {
items[i].onclick = function() {
console.log(this.innerHTML)
}
};
}
<ol id="ol">
<li>
<span class="x">hello</span>
<span class="xx">testing</span>
</li>
<li>
<span class="x">hello2</span>
<span class="xx">testing2</span>
</li>
<li>
<span class="x">hello3</span>
<span class="xx">testing4</span>
</li>
<li>
<span class="x">hello4</span>
<span class="xx">testing4</span>
</li>
</ol>
<button onclick="myfunction()">click</button>
Rather than placing a listener on each li, you can take advantage of event delegation, placing a single handler on the ol:
<ol id="ol">
<li>
<span class="x">hello</span>
<span class="xx">testing</span>
</li>
<li>
<span class="x">hello2</span>
<span class="xx">testing2</span>
</li>
<li>
<span class="x">hello3</span>
<span class="xx">testing4</span>
</li>
<li>
<span class="x">hello4</span>
<span class="xx">testing4</span>
</li>
</ol>
<button id="button">click</button>
'use strict';
const button = document.querySelector('#button');
const findLI = el => {
if (el.tagName.toLowerCase() === 'li') {
return el;
}
return findLI(el.parentElement);
};
const registerItemsClickHandler = () => {
const ol = document.querySelector('#ol');
ol.onclick = event => {
const li = findLI(event.target);
console.log(li.innerHTML);
};
};
button.onclick = registerItemsClickHandler;
Notice that we only register a single click handler (on the ol) and that we can use event.target to determine the specific element onto which the event was dispatched. It's also worth noting that a child any depth of the tree can be a dispatch target, so we can use the recursive findLI() function to find the first parent that is an li, if el itself isn't one.

function for adding new contacts won't work

I watched a youtube video about coding in vanilla javascript because I'm currently studying javascript. I wanted to add an "adder" for names that start with letter a.
I wrote a do1 function and I added div between all names that start with a. I don't know what's going on here to be host what's the problem. I'm currently moving from basics to intermediate level in javascript, I'm trying to practice my javascript skills in any possible way. function filter names was written by someone else. I don't have that much skills to do something like that.
So if you have any ideas on how should I practice js. If you have any websites or even tasks that could help me in learning javascript. would appreciate if you linked me any in comments section.
let filterInput = document.getElementById('filterInput');
filterInput.addEventListener('keyup', filterNames);
function filterNames() {
// Get value of input
let filterValue = document.getElementById('filterInput').value.toUpperCase();
// Get names ul
let ul = document.getElementById('names');
// Get lis from ul
let li = ul.querySelectorAll('li.collection-item');
// Loop through collection-item lis
for (let i = 0; i < li.length; i++) {
let a = li[i].getElementsByTagName('a')[0];
// If matched
if (a.innerHTML.toUpperCase().indexOf(filterValue) > -1) {
li[i].style.display = '';
} else {
li[i].style.display = 'none';
}
}
}
function do1() {
var input1 = document.getElementById('ipt1').value;
var item = document.createTextNode(input1);
var li = document.createElement('li').className = "collection-header";
var a = document.createElement('a');
var child1 = li.appendChild(a);
var div = document.getElementById('div1');
div1.appendChild(item).innerHTML = item;
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.99.0/css/materialize.css">
<div class="container">
<h1 class="center-align">
My Contacts
</h1>
<input type="text" id="filterInput" placeholder="Search names...">
<ul id="names" class="collection with-header">
<li class="collection-header">
<h5>A</h5> <input type="box" id="ipt1"> <button onclick="do1();">`click me to add another contact`</button>
</li>
<div id="div1">
<li class="collection-item">
Abe
</li>
<li class="collection-item">
Adam
</li>
<li class="collection-item">
Alan
</li>
<li class="collection-item">
Anna
</li>
</div>
<li class="collection-header">
<h5>B</h5> <input type="box" id="ipt2">
</li>
<li class="collection-item">
Beth
</li>
<li class="collection-item">
Bill
</li>
<li class="collection-item">
Bob
</li>
<li class="collection-item">
Brad
</li>
<li class="collection-header">
<h5>C</h5> <input type="box" id="ipt3">
</li>
<li class="collection-item">
Carrie
</li>
<li class="collection-item">
Cathy
</li>
<li class="collection-item">
Courtney
</li>
</ul>
</div>
Here is a working example:
let filterInput = document.getElementById("filterInput");
filterInput.addEventListener("keyup", filterNames);
function filterNames() {
// Get value of input
let filterValue = document.getElementById("filterInput").value.toUpperCase();
// Get names ul
let ul = document.getElementById("names");
// Get lis from ul
let li = ul.querySelectorAll("li.collection-item");
// Loop through collection-item lis
for (let i = 0; i < li.length; i++) {
let a = li[i].getElementsByTagName("a")[0];
// If matched
if (a.innerHTML.toUpperCase().indexOf(filterValue) > -1) {
li[i].style.display = "";
} else {
li[i].style.display = "none";
}
}
}
function do1() {
var input1 = document.getElementById("ipt1").value;
var a = document.createElement("a");
a.textContent = input1;
a.setAttribute('href', "#");
var li = (document.createElement("li"));
li.setAttribute('class', 'collection-item');
li.appendChild(a);
var div = document.getElementById("div1");
div1.appendChild(li);
}
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.99.0/css/materialize.css">
<div class="container">
<h1 class="center-align">
My Contacts
</h1>
<input type="text" id="filterInput" placeholder="Search names...">
<ul id="names" class="collection with-header">
<li class="collection-header">
<h5>A</h5> <input type="box" id="ipt1"> <button onclick="do1();">`click me to add another contact`</button>
</li>
<div id="div1">
<li class="collection-item">
Abe
</li>
<li class="collection-item">
Adam
</li>
<li class="collection-item">
Alan
</li>
<li class="collection-item">
Anna
</li>
</div>
<li class="collection-header">
<h5>B</h5> <input type="box" id="ipt2">
</li>
<li class="collection-item">
Beth
</li>
<li class="collection-item">
Bill
</li>
<li class="collection-item">
Bob
</li>
<li class="collection-item">
Brad
</li>
<li class="collection-header">
<h5>C</h5> <input type="box" id="ipt3">
</li>
<li class="collection-item">
Carrie
</li>
<li class="collection-item">
Cathy
</li>
<li class="collection-item">
Courtney
</li>
</ul>
</div>
The issues you were having
var item = document.createTextNode(input1); // this line was not needed as you already had the text
var li = document.createElement('li').className = "collection-header"; // assigning a string here causing errors. Use setAttribute() not class name.
div1.appendChild(item).innerHTML = item; assigning to innerHTML of appended child
so changing the function from:
function do1() {
var input1 = document.getElementById('ipt1').value;
var item = document.createTextNode(input1);
var li = document.createElement('li').className = "collection-header";
var a = document.createElement('a');
var child1 = li.appendChild(a);
var div = document.getElementById('div1');
div1.appendChild(item).innerHTML = item;
}
to :
function do1() {
var input1 = document.getElementById("ipt1").value; // get the value of the input
var a = document.createElement("a"); // create new a tag
a.textContent = input1; // Set the text of the a tag
a.setAttribute('href', "#"); // Set the href attribute of the a tag
var li = (document.createElement("li")); // Create new list item
li.setAttribute('class', 'collection-item'); // Set class attribute of li tag
li.appendChild(a); // Append the a tag to the list item
var div = document.getElementById("div1"); // get the containing div
div1.appendChild(li); // append the new list item to the div
}
Now you are able to append to the first div around A. To append to others, you first would need div tags with different ID's. Then you would just need to either create a new function for each one or pass which div ID you were calling the method on..
Hope this helps.
Look at the following line of code:
var li = document.createElement('li').className = "collection-header";
This code assigns the string "collection-header" to the variable named li. Strings don't have the appendChild function, so your code is crashing on the line:
var child1 = li.appendChild(a);
Not sure what your intention is by using two = in the same line of code. If you can explain that further, perhaps someone can help you achieve your desired result.

Javascript how to get list is on click on inner span

<li id="123">
<span id="tst">test</span>
</li>
I have the above code. I would like to get the li id on click on span id. Is it possible to do so?
Most easily to do with jQuery:
$('span').click(function() {
var parentId = $(this).closest('li').attr('id');
console.log(parentId);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<li id="123">
<span id="tst">test</span>
</li>
Or as plain vanilla js:
document.getElementById('tst').onclick = function() {
var parentId = this.parentElement.id;
console.log(parentId);
};
<li id="123">
<span id="tst">test</span>
</li>

Trying to find the nearest date today in a <ul>

I am trying to find the next/nearest date to today from a list of dates and then add a class to it and display that item in another place.
<ul class="locations">
<li>
<span class="date">01-Jun-2015</span>
<span class="location">London</span>
</li>
<li>
<span class="date">15-Jun-2015</span>
<span class="location">Paris</span>
</li>
<li>
<span class="date">03-Jul-2015</span>
<span class="location">Berlin</span>
</li>
<li>
<span class="date">16-Jun-2015</span>
<span class="location">Milan</span>
</li>
<li>
<span class="date">20-Jul-2015</span>
<span class="location">Madrid</span>
</li>
<li>
<span class="date">07-Aug-2015</span>
<span class="location">Lisbon</span>
</li>
</ul>
<p class="next-date">
Next date and location:
</p>
Please can someone help point me in the right direction?
I assume you'd be okay with jQuery as your question is tagged so. You could find the nearest future date to today using a couple of in-built functions, such as Date(), Array.sort() and $.map() as below. Pls look at the comments in the script for more info about the code.
var $locations = $(".locations");
//Today's date in milliseconds
var tsToday = new Date().getTime();
//Create an array of timestamps using .map
var allDatesTimestamp = $locations.find(".date").map(function() {
//Convert text to date in milliseconds
var ts = new Date($(this).text()).getTime();
//Return only those timestamps that are greater than today
//And sort them to get the smallest/nearest timestamp as the first array item
if (ts > tsToday) {
return ts;
}
}).get().sort();
//Find all .date elements and filter out
var $elem = $locations.find(".date").filter(function() {
//Filter out the one where date equals to first item in the array as that's the nearest
return new Date($(this).text()).getTime() === allDatesTimestamp[0]
//Return the sarrounding element
//Add a class if need be, to highlight it
}).closest("li").addClass("nearest");
//Rest is simple; find and display.
$(".next-date")
.append("Date: " + $elem.find(".date").text())
.append("<br/>Location: " + $elem.find(".location").text());
.locations .nearest {
color: green;
font-size: 1.5em;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="locations">
<li>
<span class="date">01-Jun-2015</span>
<span class="location">London</span>
</li>
<li>
<span class="date">15-Jun-2015</span>
<span class="location">Paris</span>
</li>
<li>
<span class="date">03-Jul-2015</span>
<span class="location">Berlin</span>
</li>
<li>
<span class="date">16-Jun-2015</span>
<span class="location">Milan</span>
</li>
<li>
<span class="date">20-Jul-2015</span>
<span class="location">Madrid</span>
</li>
<li>
<span class="date">07-Aug-2015</span>
<span class="location">Lisbon</span>
</li>
</ul>
<p class="next-date">
<strong>Next date and location: </strong><br/>
</p>
Hope that helps.
I wrote a custom sort function to sort the closet next date
dates.sort(function(x, y) {
if (x[0]-Date.now() < 0) {
return 1;
}
if (x[0]-Date.now() < y[0]-Date.now()) {
return -1;
}
if (x[0]-Date.now() > y[0]-Date.now()) {
return 1;
}
return 0;
});
http://codepen.io/anon/pen/Kpqvxv
Try using Date() for comparison:
$(function() {
var now = new Date().getTime(); //get current time
var li, diff, sp, tmp;
$('span.date').each(function() {//loop in all dates
sp = $(this);
if (!li) {// first time
li = sp.closest('li'); // get parent of date
diff = Math.abs(now - new Date(sp.text()).getTime()); //get differnce
return;
}
tmp = Math.abs(now - new Date(sp.text()).getTime());
if (tmp < diff) { // this is close to current date
diff = tmp;
li = sp.closest('li');
}
});
li.addClass('now'); // highlight
$('p.next-date').text(function() {
return this.innerHTML + li.text(); // update date and place
});
});
.now {
background-color: orange;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<ul class="locations">
<li>
<span class="date">01-Jun-2015</span>
<span class="location">London</span>
</li>
<li>
<span class="date">15-Jun-2015</span>
<span class="location">Paris</span>
</li>
<li>
<span class="date">03-Jul-2015</span>
<span class="location">Berlin</span>
</li>
<li>
<span class="date">16-Jun-2015</span>
<span class="location">Milan</span>
</li>
<li>
<span class="date">20-Jul-2015</span>
<span class="location">Madrid</span>
</li>
<li>
<span class="date">07-Aug-2015</span>
<span class="location">Lisbon</span>
</li>
</ul>
<p class="next-date">
Next date and location:
</p>

jQuery Higlight items that are more than one in ul

I am trying to highlight items that are more than one in a list with different colours with jQuery. Is below achievable easily?
For example. Take the ul below
<ul id="inul">
<li id="s0" class="list">
<span id="ip0">127.0.0.1</span>
<span id="ua0">SonyEricssonK800iv/R1KG Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1</span>
</li>
<li id="s1" class="list">
<span id="ip1">127.0.0.1</span>
<span id="ua1">Nokia3120classic/2.0 (09.41) Profile/MIDP-2.1 Configuration/CLDC-1.1 nokia3120classic/UC Browser7.6.1.82/69/352 UNTRUSTED/1.0</span>
</li>
<li id="s2" class="list">
<span id="ip2">127.0.0.1</span>
<span id="ua2">SonyEricssonW580i/R8BE Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1</span>
</li>
<li id="s3" class="list">
<span id="ip3">127.0.0.1</span>
<span id="ua3">SonyEricssonK800iv/R1KG Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1</span>
</li>
<li id="s4" class="list">
<span id="ip4">127.0.0.1</span>
<span id="ua4">Nokia3120classic/2.0 (09.41) Profile/MIDP-2.1 Configuration/CLDC-1.1 nokia3120classic/UC Browser7.6.1.82/69/352 UNTRUSTED/1.0</span>
</li>
<li id="s5" class="list">
<span id="ip5">127.0.0.2</span>
<span id="ua5">SonyEricssonW580i/R8BE Browser/NetFront/3.3 Profile/MIDP-2.0 Configuration/CLDC-1.1</span>
</li>
</ul>
There are two of each browser user agent and 4 of same ip (127.0.0.1) and 1 127.0.0.2.
What i am hoping to achieve is that identical spans would be colored with same color while assigning different color to each identical set.
Just to be clear, end result should look like image below
UPDATE With the help of WSkid I ahve manged to achive what i want. See update http://pastebin.ca/2058058 or working version at http://jsfiddle.net/mUGVR/15/
The following is terribly in efficient and hacky, but it might start you down the right road of storing a hash-like map and keeping a count to add your needed styles:
Working fiddle http://jsfiddle.net/mUGVR/.
var ipList={};
var ipCount=0;
var userList={};
var userCount=0;
$('li.list').each(function(i){
var spans = $(this).children();
spans[0] = $(spans[0]);
spans[1] = $(spans[1]);
if(ipList[spans[0].text()]!=null)
{
spans[0].addClass('ip'+ipList[spans[0].text()]);
}
else
{
ipList[spans[0].text()] = ipCount;
spans[0].addClass('ip'+ipCount);
ipCount++;
}
if(userList[spans[1].text()]!=null)
{
spans[1].addClass('user'+userList[spans[1].text()]);
}
else
{
userList[spans[1].text()] = userCount;
spans[1].addClass('user'+userCount);
userCount++;
}
});
With css:
.ip0 {background:yellow;}
.user0{background:cyan;}
.user1{background:green;}
.user2{background:red;}
Like this? Fiddle: http://jsfiddle.net/8A5dY/1
// highlights ips
$('li span:first-child').filter(function() {
return ($(this).text() == '127.0.0.1');
}).css('background', 'yellow');
var colorMap = [];
var currentColor = 0;
$('li span:nth-child(2)').each(function() {
var text = $(this).text();
var color = colorMap[text] ||
['lightblue', 'red', 'blue', 'green'][currentColor++];
colorMap[text] = color;
$(this).css('background', color);
});

Categories