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));
}
});
Related
var ul = document.getElementById("parent-list");
document.querySelectorAll("#parent-list li").onclick = function() {
alert('click!');
}
<ul id="parent-list">
<li id="item-1">Item 1</li>
<li id="item-2">Item 2</li>
<li id="item-3">Item 3</li>
<li id="item-4">Item 4</li>
<li id="item-5">Item 5</li>
<li id="item-6">Item 6</li>
<li id="item-7">Item 7</li>
<li id="item-8">Item 8</li>
<li id="item-9">Item 9</li>
</ul>
I'm trying to have an alert popup of the item clicked when I click on a "li" element with javascript only. I know how to do in jquery but I can't figure out how to do it with javascript.
fiddle: https://jsfiddle.net/7jcksznz/1/
querySelectorAll returns an HTML collection. You would need to attach the event to each one. You would need to loop over the collection.
var lis = document.querySelectorAll("#test li");
for (var i = 0; i < lis.length; i++) {
lis[i].addEventListener("click", function() {
console.log(this.innerHTML);
});
}
<ul id="test">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
A better option is to add one click on the UL and use the event to determine which li was clicked.
document.getElementById("test").addEventListener("click", function(event) {
var li = event.target;
console.log(li.innerHTML);
});
<ul id="test">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
document.querySelectorAll("#parent-list li") get a collection of HTMLElement,so,you can do like this:
window.onload = function()
{
var ul = document.getElementById("parent-list");
ul.onclick = function(e)
{
if(e.target.tagName = "LI")
{
alert(1);
}
}
}
querySelectAll returns array of nodes.
you have to iterate over the nodes to add the event listner.
var ul = document.getElementById("parent-list");
var li_items = document.querySelectorAll("#parent-list li");
for (var i = 0 ; i < li_items.length ; i++)
li_items[i].onclick = function (){alert(this.id);}
Use an event-listener targeted on each element rather than directly assigning an onclick function to a NamedNodeMap.
/* get an array of list items */
var items = Array.prototype.slice.call(
document.querySelectorAll('li[id|="item"]')
);
/* add event-listener to each item */
items.forEach(function(item) {
item.addEventListener('click', clickAlert, false);
});
/* click function */
function clickAlert(evt) {
alert(evt.target.id +' clicked!');
}
See:
Array.prototype.slice
Array.prototype.forEach
eventTarget.addEventListener
NamedNodeMap
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
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
}
}
Please take a look at this FIDDLE. I have two pairs of unordered lists, each of which is inside a div element.pricing-table. The following code can find the li with the same classes, get the max height and set the height of all of them to the same. But I want to limit it to getting the max-height of each pair of lists inside each div element.
I think this line is giving me problem because it is getting all the lists with the same classes in the document:
var elems = $('.pricing-table ul li.' + elem.className),
I don't think I can use $(this) and update it like $(this +elem.className). Any suggestions?
Jquery script:
$(document).ready( function(){
$('.pricing-table ul li').each(function(i, elem) {
var elems = $('.pricing-table ul li.' + elem.className),
heights = $.map(elems, function(li) {
return $(li).height();
}),
max = Math.max.apply(null, heights);
elems.height(max);
});
});
HTML
<div class="pricing-table">
<ul>
<li class="heading">Bronze</li>
<li class="year">2003<p>(Text)..........</li>
<li class="package">Starter package</li>
<li class="location">Africa (Text).......)</li>
<li class="description">Text............ </li>
</ul>
<ul class="feature">
<li class="heading">Silver</li>
<li class="year">2004</li>
<li class="package">Intermediate package</li>
<li class="location">Asia</li>
<li class="description">Text............ </li>
</ul>
</div>
<div class="pricing-table">
<ul>
<li class="heading">Bronze</li>
<li class="year">2003<p>(Text)..........</li>
<li class="package">Starter package</li>
<li class="location">Africa (Text).......)</li>
<li class="description">Text............ </li>
</ul>
<ul class="feature">
<li class="heading">Silver</li>
<li class="year">2004</li>
<li class="package">Intermediate package</li>
<li class="location">Asia</li>
<li class="description">Text............ </li>
</ul>
</div>
You’d need to get only the li that are descendants of your current .pricing-table element, so you’ll have to iterate over the latter first:
$(document).ready(function () {
$('.pricing-table').each(function (i, e) {
$(e).find('ul li').each(function (i, elem) {
var elems = $(e).find('ul li.' + elem.className),
heights = $.map(elems, function (li) {
return $(li).height();
}),
max = Math.max.apply(null, heights);
elems.height(max);
});
});
});
… or something like that. http://jsfiddle.net/p3sfy/3867/
(Still kinda ugly, since it will iterate over the li multiple times, so that’s rather just a “quick fix” – but I don’t wanna think about anything more sophisticated here before I have not first heard a convincing argument why this data is not marked up using tables in the first place …?)
I have this HTML:
<ul class="parent">
<ul>
<li>
<ul></ul>
</li>
<li>
<ul>
<li>
<ul></ul>
</li>
</ul>
</li>
</ul>
</ul>
I need to add count classes for all nested lists in this markup, to reach this:
<ul class="parent">
<ul class="level-1">
<li>
<ul class="level-2"></ul>
</li>
<li>
<ul class="level-2">
<li>
<ul class="level-3"></ul>
</li>
</ul>
</li>
</ul>
<ul class="level-1">
<li>
<ul class="level-2"></ul>
</li>
<li>
<ul class="level-2">
<li>
<ul class="level-3"></ul>
</li>
</ul>
</li>
</ul>
</ul>
So i do this:
var parent_ul = $('.parent');
if (parent_ul.doesExist()){
var parent_ul_lists = parent_ul.find('ul');
parent_ul_lists.each(function(){
var i;
for (i = 0; i < parent_ul_lists.length; i++) {
$(this).eq(i).addClass('level-' + i);
}
})
}
But in output i have class test level-1 for all of parent list childrens. Can anybody help?
Try this
$('.parent ul').addClass(function(){
return "level-"+$(this).parents('ul').length;
});
DEMO
Try this
var parent = $('.parent').children();
next = parent;
var i = 0;
while (next.length) {
parent = next;
parent.addClass("Level_" + i);
i++;
next = next.children();
}
Demo
You need some good 'ole recursion!
Check out this JSFiddle UPDATE: corrected jsFiddle link
Here is the code:
function labelChildUL(element, count) {
element.children().each(function (index, value) {
var $me = $(value);
if ($me.is("ul")) {
$me.addClass("level-" + (count + 1));
labelChildUL($me, count + 1);
}
else
{
labelChildUL($me, count);
}
});
}
$(document).ready(function () {
var $parent = $('#parent');
labelChildUL($parent, 0);
});
I also updated your html to use id instead of class for "parent":
<ul id='parent'>
...
You can use this;
var parent_ul = $('.parent');
var parent_ul_lists = parent_ul.find('ul');
parent_ul_lists.each(function(){
$(this).addClass('level-'+ ($(this).parents().length -1)/2);
});
See working demo here: http://jsfiddle.net/huseyinbabal/qmGcC/
Note: Inspect element in output to see class assigned