I have a big list <li> of items and a button to "shuffle" the list, what I'm trying to achieve is, show only 3 RANDOM list items when the page loads, then on button click, shuffle the list, hide the current 3 list items and show OTHER RANDOM list items.
What I did till now is this, but it doesn't really do everything I'm trying to achieve, I get 3 items showed only, but they get randomised between the same 3 list items always...
$('.fr_revs > li').hide().filter(':lt(3)').show();
var ul = document.querySelector('.fr_revs');
for (var i = ul.children.length; i >= 0; i--) {
ul.appendChild(ul.children[Math.random() * i | 0]);
}
Can somebody help me please. Thank you
Try something like this
var ul = $('ul'),
lis = ul.find('li').detach(),
button = $('#shuffle'),
used = [];
function showRandom() {
var new_lis = [];
while (true) {
var li = lis[Math.floor(Math.random() * lis.length)];
if (used.indexOf(li) === -1 && new_lis.indexOf(li) === -1) new_lis.push(li);
if (new_lis.length >= 3) break;
}
used = new_lis;
ul.html(new_lis);
}
button.click(showRandom);
showRandom();
You need to have six or more <li> elements, otherwise it will be an infinite while (true) loop.
Hide all items at first. Then generate 3 random number and select item with index using .eq() and show selected items.
$(".fr_revs > li").hide();
randomItem();
$("button").click(function(){
var lastItems = $(".fr_revs > li:visible");
randomItem();
lastItems.hide();
});
function randomItem(){
for (var i = 0; i < 3; i++){
var length = $(".fr_revs > li:not(:visible)").length;
var random = Math.floor(Math.random() * length);
$(".fr_revs > li:not(:visible)").eq(random).show();
}
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button>Get new</button>
<ul class="fr_revs">
<li>A</li>
<li>B</li>
<li>C</li>
<li>D</li>
<li>E</li>
<li>F</li>
<li>G</li>
<li>H</li>
<li>I</li>
<li>J</li>
<li>K</li>
<li>L</li>
<li>M</li>
<li>N</li>
<li>O</li>
</ul>
try this simple answer, it is very easy and here is the working demo
<html>
<head></head>
<title></title>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.12.4/jquery.min.js"></script>
<style type="text/css">
</style>
<body>
<input type="button" value="click to shuffle" id="shuffle">
<ul class="mylist">
<li id="id1">one</li>
<li id="id2">two</li>
<li id="id3">three</li>
<li id="id4">four</li>
<li id="id5">five</li>
<li id="id6">six</li>
<li id="id7">seven</li>
<li id="id8">eight</li>
<li id="id9">nine</li>
<li id="id10">ten</li>
<li id="id11">eleven</li>
<li id="id12">twelve</li>
</ul>
</body>
<script type="text/javascript">
$(document).ready(function(){
$("ul.mylist li").slice(3).hide();
var theCount = 3;
$("#shuffle").click(function(){
$("ul.mylist li").hide();
var theLength = $("ul.mylist li").length;
if(theCount == theLength)
{
theCount = 3;
}
else
{
theCount = theCount + 3;
}
$("ul.mylist li").slice(theCount-3,theCount).show();
});
});
</script>
</html>
note: in here, length(number of elements inside the ul) should be a number which can devide from 3, because you want to show 3 per time
Related
I have the following list:
<ul>
<li class="item">One</li>
<li class="item">Two</li>
<li class="item">Three
<ul>
<li class="item">Something Original</li>
<li class="item selected">Something</li>
</ul>
</li>
<li>Four
<ul>
<li class="item">I want this selected next</li>
<li class="item">Good</li>
</ul>
</li>
</ul>
Using jQuery, how do I find the next li with the class="item" since it is wrapped in a different container. Obviously I cannot do $(".selected").next(".item") so how else can I do it?
JSFiddle: http://jsfiddle.net/q3f6v7zz/
Since the li elements are nested and you know that you want the next appearing li with a particular class, you can use .index() and do something like this
var $li = $('.item'); // <--- get the list of all lis with class .item
var index = $li.index($('.selected')); // <--- find the index of the one with .selected amongst all the lis
console.log($li.eq(index+1).html()); // <--- index+1 because you need the next appearing li after selected
If you want to move the selected class on keydown something like this should do
var $li = $('.item');
$(document).on('keydown', function(e) {
if (e.keyCode == 40) {
var index = $li.index($('.selected'));
$li.eq(index).removeClass('selected');
index = (index+1) % $li.length; // <--- to rotate the values from 0 to count of li.item elements
$li.eq(index).addClass('selected');
}
});
var $li = $('.item');
$(document).on('keydown', function(e) {
if (e.keyCode == 40) {
var index = $li.index($('.selected'));
$li.eq(index).removeClass('selected');
index = (index+1) % $li.length;
$li.eq(index).addClass('selected');
}
});
.selected {
background: green;
color: white;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<ul>
<li class="item">One</li>
<li class="item">Two</li>
<li>Three
<ul>
<li class="item">Something</li>
<li class="item selected">Something Else</li>
</ul>
</li>
<li>Four
<ul>
<li class="item">I want this selected next</li>
<li class="item">Good</li>
</ul>
</li>
</ul>
You can get the index of the selected element within all lis, and then increment that index to get the next one.
$("ul").on("click", "li.item.selected", function() {
var all_li = $("li.item");
var selected_index = all_li.index(this);
var next_li = all_li.eq((selected_index + 1) % all_li.length);
$(this).removeClass("selected");
next_li.addClass("selected");
});
.item.selected {
background-color: yellow;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="item">One</li>
<li class="item">Two</li>
<li class="item">Three
<ul>
<li class="item selected">Something</li>
</ul>
</li>
<li>Four
<ul>
<li class="item">I want this selected next</li>
<li class="item">Good</li>
</ul>
</li>
</ul>
I used the modulus so it will wrap around at the end.
Not sure what you are exactly looking for but you can use $(Element").parent().parent().find("li");
So in other words .parent() may be what you are looking for there is also .sibling() to find or you may want $('li').closest('ul').find('li')
which will go up the tree to find the nearest ul to the one you are looking for
https://api.jquery.com/closest/
You may also use:
Vanilla JS to do something similar to what was discussed by others with $index if it makes more sense to you:
Again this isn't as efficient but that is basically what JQuery is doing:
var myLis = document.getElementsByTagName('li');
var wantedIndex;
for(var i = 0;i<myLis.length; i++){
if(myLis[i].className === "active"){
wantedIndex = i+1; //gets the li which is next when selecting all lis
}
}
I've a nested (UL->LI->UL-LI..) list. On any clicked node, I'm using ParentsUntil() to find all the parents till a certain ancestor element.
In each nested element's data attribute (data-weight:), there is number that represent weight.
I want to sum/aggregate total weight till the parent. These numbers (Areas) are in the data-area field of each item.
<ul class="level-1 yes" data-weight="12" data-weight-total="0">
<li class="item-i" data-weight="22" >I</li>
<li class="item-ii" data-weight="4" data-weight-total="0">II
<ul class="level-2 yes" data-weight="12">
<li class="item-a" data-weight="1.4">A</li>
<li class="item-b" data-weight="128" data-weight-total="0">B
<ul class="level-3" data-weight="63" data-weight-total="0">
<li class="item-1" data-weight="54">1</li>
<li class="item-2" data-weight="23">2</li>
<li class="item-3" data-weight="107">3</li>
</ul>
</li>
<li class="item-c" data-weight="231">C</li>
</ul>
</li>
<li class="item-iii">III</li>
</ul>
$( "li.item-2" )
.parentsUntil( $( "ul.level-1" ), ".yes" );
In the list above,
How can I get the an array/list of them items from the clicked item
to the parent item with their data-weight [key,value]? for e.g. $VarArrayCargoVessel
And as I traverse up, How can I sum/total weights (data-weight-total) of each/nested list and populate\fill-in the data-weight-total? I have zero's right now, because I dont know how to insert/write into a array value
$("li").click(function(event){
event.stopPropagation();
var list = $(this).closest("ul");
var children = list.children();
var values = [];
for(var i = 0; i < children.length; i++){
values.push(parseInt((children[i].getAttribute("data-weight") !== null) ? children[i].getAttribute("data-weight") : "0"));
}
var sum = 0;
for(var j = 0; j < values.length; j++){
sum += values[j];
}
$("#summed").html(sum);
});
li{
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="level-1 yes" data-weight="12" data-weight-total="0">
<li class="item-i" data-weight="22" >I</li>
<li class="item-ii" data-weight="4" data-weight-total="0">II
<ul class="level-2 yes" data-weight="12">
<li class="item-a" data-weight="1.4">A</li>
<li class="item-b" data-weight="128" data-weight-total="0">B
<ul class="level-3" data-weight="63" data-weight-total="0">
<li class="item-1" data-weight="54">1</li>
<li class="item-2" data-weight="23">2</li>
<li class="item-3" data-weight="107">3</li>
</ul>
</li>
<li class="item-c" data-weight="231">C</li>
</ul>
</li>
<li class="item-iii">III</li>
</ul>
<div id="summed"></div>
Okay, let's get through this step by step. The first thing we do is creating a click event for each "li" item. If a li item is clicked, we execute our function ("function(event)").
The first line stops the event from propagating up. jQuery would go up to the very first "ul" item otherwise and execute the code for each "ul" element. We would receive the first list all the time.
http://api.jquery.com/event.stopPropagation/
We then get the closest "ul" element and store this in the variable "list". We don't want the list itself, that's why we store its children ("li" elements) in the variable "children".
We loop then through each children and store the "data-weight" attribute (method "getAttribute") in the array "values". Note that we only store the attribute if it's actually exists. If not, we just store "0".
https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute
We then create a variable "sum" which stores our summed up attributes. To do so we loop through the array and add the value (+= values[j]) to the sum variable.
The last step writes the sum variable in the html of the div with the id #summed (check the html section).
Further reading:
https://developer.mozilla.org/en-US/docs/Web/API/Element/getAttribute
http://api.jquery.com/closest/
http://api.jquery.com/click/
http://api.jquery.com/event.stopPropagation/
http://api.jquery.com/children/
http://www.sitepoint.com/shorthand-javascript-techniques/
http://api.jquery.com/html/
Version 2:
$("li").click(function(event){
event.stopPropagation();
var list = $(this).find("ul").first();
console.log(list);
var children = list.children();
var values = [];
for(var i = 0; i < children.length; i++){
values.push(parseInt((children[i].getAttribute("data-weight") !== null) ? children[i].getAttribute("data-weight") : "0"));
}
var sum = 0;
for(var j = 0; j < values.length; j++){
sum += values[j];
}
$("#summed").html(sum);
});
li{
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="level-1 yes" data-weight="12" data-weight-total="0">
<li class="item-i" data-weight="22" >I</li>
<li class="item-ii" data-weight="4" data-weight-total="0">II
<ul class="level-2 yes" data-weight="12">
<li class="item-a" data-weight="1.4">A</li>
<li class="item-b" data-weight="128" data-weight-total="0">B
<ul class="level-3" data-weight="63" data-weight-total="0">
<li class="item-1" data-weight="54">1</li>
<li class="item-2" data-weight="23">2</li>
<li class="item-3" data-weight="107">3</li>
</ul>
</li>
<li class="item-c" data-weight="231">C</li>
</ul>
</li>
<li class="item-iii">III</li>
</ul>
<div id="summed"></div>
Note the third line in the answer. I've changed it to:
var list = $(this).find("ul").first();
Version 3:
$("li").click(function(event){
event.stopPropagation();
var children = $(this).find("ul").first().children();
if(children.length === 0){
children = $(this);
}
console.log(children);
var values = [];
for(var i = 0; i < children.length; i++){
values.push(parseFloat((children[i].getAttribute("data-weight") !== null) ? children[i].getAttribute("data-weight") : "0"));
}
var sum = 0;
for(var j = 0; j < values.length; j++){
sum += values[j];
}
$("#summed").html(sum);
});
li{
cursor: pointer;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="level-1 yes" data-weight="12" data-weight-total="0">
<li class="item-i" data-weight="22" >I</li>
<li class="item-ii" data-weight="4" data-weight-total="0">II
<ul class="level-2 yes" data-weight="12">
<li class="item-a" data-weight="1.4">A</li>
<li class="item-b" data-weight="128" data-weight-total="0">B
<ul class="level-3" data-weight="63" data-weight-total="0">
<li class="item-1" data-weight="54">1</li>
<li class="item-2" data-weight="23">2</li>
<li class="item-3" data-weight="107">3</li>
</ul>
</li>
<li class="item-c" data-weight="231">C</li>
</ul>
</li>
<li class="item-iii">III</li>
</ul>
<div id="summed"></div>
Look into the following jQuery methods, they are all you need:
each (link),
attr (link),
find (link) / children (link)
For example, at page load, you want to find each node that has a data-weight-total attribute, go through all its (immediate or all) children that have a data-weight attribute, get the sum of them and assign it to the node's data-weight-total property. If you want only immediate children, you would use .children(), or for all you would use .find():
$( document ).ready(function(){ // DOM ready
$('[data-weight-total]').each(function(){
var total = 0;
$(this).find('[data-weight]').each(function(){
total = total + parseInt($(this).attr('data-weight'));
});
$(this).attr('data-weight-total',total);
});
})
This would calculate and assign data-weight-total values to all nodes that have such an attribute, as soon as the document is loaded. Let me know if you need explanations for any of what's going on in the function.
All Imtrying to do is have a loop to iterate over my nav elements, and every second check the data-time to the variable being counted, and change a div to have the text within the list item. Ill already have the list in increasing order so that wont be a issue.
Ive tried 40 different ways to do this and this is my cloest to working solution, it just sets the innerHTML of the div to whitespace and I dont now why.
<DOCTYPE! Html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
var navList = document.getElementsByClassName("nav");
var y = 0;
for(x = 0; x< 50; x++){
var timeCheck = navList[y].getAttribute("data-time");
setTimeout(function(){
if (timeCheck == x){
document.getElementById('itemHtml').innerHTML = navList[y].innerHTML;
y++;
}
},1000);
}
});
</script>
</head>
<body>
<ul>
<li class="nav" data-time="4"> test 1</li>
<li class="nav" data-time="8"> test 2</li>
<li class="nav" data-time="14"> test 3</li>
<li class="nav" data-time="18"> test 4</li>
</ul>
<div>
<h3 id="itemHtml"> placeholder </h3>
<h3 id="test"> placeholder </h3>
</div>
</body>
</html>
By the time your setTimeout executes, the for loop has most likely already gone through all elements. Also it creates a closure, so the x values will not be what you expect it to be. Last but not least, setTimeout executes once after the specified time, you want to use setInterval.
So what you are trying to do is check every second if time has eclipsed up to that date-time of any element? If so use an interval not a set timeout. Also have the loop within each execution of the interval.
var navList = document.getElementsByClassName("nav");
var y = 0;
var timeCount = 0;
setInterval(function(){ // Create an interval with a function payload.
timeCount++; // Increment the times hit. This is an an approx of number of seconds
for(x = 0; x< navList.length; x++){
var timeCheck = navList[y].getAttribute("data-time");
console.log('timeCheck: ' + timeCheck + ' timeCount ' + timeCount);
if(timeCheck == timeCount){ // Have we found a match for this current second?
console.log('found a match');
console.log(navList[y].innerHTML);
document.getElementById('itemHtml').innerHTML = navList[y].innerHTML;
y++;
}
}
}, 1000); // run interval every second.
http://jsfiddle.net/3pop4g76/4/
What I ended up using for those interested.
<DOCTYPE! Html>
<html>
<head>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
var navList = document.getElementsByClassName("nav");
var y = 0;
var x = 0;
var test = setInterval(function(){
x++;
var timeCheck = navList[y].getAttribute("data-time");
if (timeCheck == x){
document.getElementById('itemHtml').innerHTML = navList[y].innerHTML;
y++;
}
if(x == 10){clearInterval(test)}
},1000);
});
</script>
</head>
<body>
<ul>
<li class="nav" data-time="4"> test 1</li>
<li class="nav" data-time="8"> test 2</li>
<li class="nav" data-time="14"> test 3</li>
<li class="nav" data-time="18"> test 4</li>
</ul>
<div>
<h3 id="itemHtml"> placeholder </h3>
<h3 id="test"> placeholder </h3>
</div>
</body>
</html>
I have a ul list as follows. I am new to JS and trying to do a keyboard navigation, just the arrow keys using only javascript.
<ul id= nav>
<li class =subnav id =sub1> Companies
<ul id = hidden>
<li> item 1 </li>
<li> item 2 </li>
<li> item 3 </li>
</ul>
</li>
<li class =subnav id =sub2> LINKS
<ul id = hidden>
<li> item 4 </li>
<li> item 5 </li>
<li> item 6 </li>
</ul>
</li>
</ul>
my JS:
ul = document.getElementById("nav");
li = ul.getElementsByClassName("subnav");
ul2 = document.getElementById("hidden");
li = ul.getElementsByTagName("li");
function keyPress(e)
{
var e = e||window.event;
e =e.which||e.keyCode;
for( var i=0; i<li.length; i++)
{
var f = li[i].childNodes[0];
if(li[i].children.length > 0)
{
for(var j=0; j<li2.length; j++)
{
var x = li2[j].childNodes[0];
}
}
else
{
alert("no child nodes");
}
}
}
I am trying to set focus on the first item and then moving to each nodes using keys.
I suggest using jwerty, awesome keyboard events library.
I used jQuery and jWerty plugin.
Here is a quick JSFiddle: (Click the preview window and start hitting the down key)
http://jsfiddle.net/8QZrV/
As a basic idea, you should create an object with all the elements and then iterate through them, my basic example was like this:
var i = 0;
j = jQuery('.navigator li').length;
And then you hook it up in jwerty, I guess you want to make some actions there, so I guess you should also .focus() the current element.
Enjoy!
I want to prevent my users on a cms from making their menu item go over multiple lines as it doesn't look to good and can cut off their content. I so far have this.
<div id="sitewrap">
<div id="wrap">
<ul>
<li>Home</li>
<li>About</li>
<li>Contact
<ul>
<li>Sub contact</li>
</ul>
</li>
<li>Register</li>
<li>Info</li>
<li>Share</li>
<li>Extra Info</li>
<li>Extra Info</li>
</ul>
</div>
</div>
If the width of the nav goes onto a second line I want the menu to look like this.
<div id="wrap">
<ul>
<li>Home</li>
<li>About</li>
<li>Contact</li>
<li>Register</li>
<li>
More
<ul>
<li>Share</li>
<li>Extra Info</li>
<li>Extra Info</li>
</ul>
</li>
</ul>
</div>
I am trying to achieve this with Jquery but am stuck. See Fiddle (the second list in the fiddle is how I would want it to look)
I can count the width of the list items. But I want to say if the width is > 300 add all li that come after li = 300 to a sub ul of more like I have shown above in how I want it to look like. Any help here would be appreciated.
<script>
$(document).ready(function() {
var listWidth = [];
$('#wrap ul li').each(function() {
listWidth.push($(this).width());
});
var total = 0;
for (var i = 0; i < listWidth.length; i++) {
total += parseInt(listWidth[i]);
}
if (total > 300)
{
alert ('to big');
}
else {
alert ('nice');
}
});
</script>
try something like this, FIDDLE
$(document).ready(function() {
var listWidth = [];
var total = 0;
// new li to append
var li = $('<li><a>more</a></li>')
// new ul to be appended to ul
var ul = $('<ul>')
// variable to store index of element after which new li(more) will be added
var $index = true;
// variable to state that index vaiable is set, no more index need to be set
var $value_set = true;
$('#wrap ul li').each(function() {
total += parseInt($(this).width());
if (total > 300){
if($value_set){
$index = $(this).index() - 2;
$value_set = false;
}
}
});
$( "#wrap ul li:gt("+$index +")").each(function() {
ul.append(this);
});
if(ul.length){
$('#wrap ul').append(li.append(ul));
}
});