I have a series of unordered lists wrapped in another unordered list. The task is to separate the individual li tags with commas and omitting the each list's last li tag.
I can do it on an individual list level i.e. When testing with just one list I was able to remove the last comma from the last element. But when I'm trying to apply the JavaScript in affects the last li element of the wrapping ul...
Here is my code:
<script type="text/javascript">
$(document).ready(function () {
$('.tagsList li span').each(function () {
$(this).append(',');
});
var lTag = $('.tagsList li:last span').text().replace(',','');
$('.tagsList li:last span').text(lTag);
});
</script>
<ul class="postsList">
<li>
<ul class="tagsList">
<li><span>tag1</span></li>
<li><span>tag2</span></li>
</ul>
</li>
<li>
<ul class="tagsList">
<li><span>tag1</span></li>
<li><span>tag2</span></li>
</ul>
</li>
</ul>
You should use a slightly modified selector
$('.tagsList li:not(:last-child) span').each(function () {
$(this).append(',');
});
This directly target all the span elements inside a li except the last li of each list.
demo http://jsfiddle.net/gaby/wwTjH/2/
Related
I am using the Chosen library. I have a long hierarchy select drop down list of parent and child items. It is automatically populated. I want to hide all li's containing text that starts with a dash character, example -General Discussion. I would also like to scope the hiding to only inside of the ul class name chosen-results.
<ul class="chosen-results">
//Below is the li of a child (I want to hide this li)
<li class="active-result" data-option-array-index="4">-General
Discussion</li>
//Below is the li of a parent ( I want to leave this alone)
<li class="active-result" data-option-array-index="0">Accident Prevention
</li>
</ul>
Updated. This works on node preview mode, but not in node edit mode
(function ($) {
$(document).ready(function () {
$("ul.chosen-results li").each(function () {
if ($(this).text().charAt(0) === '-') {
$(this).hide();
}
});
});
})(jQuery);
Below I tried to use .ajaxComplete, but it does not work.
(function ($) {
$(document).ajaxComplete(function() {
$("ul.chosen-results li").each(function () {
if ($(this).text().charAt(0) === '-') {
$(this).hide();
}
});
});
})(jQuery);
You can use JavaScript/jQuery to hide the li elements with the text starting with a dash character. Here is a sample code:
$(document).ready(function() {
$("ul.chosen-results li").each(function() {
if ($(this).text().charAt(0) === '-') {
$(this).hide();
}
});
});
This code will run when the document is ready and select all li elements inside the ul with the class chosen-results. It will then loop through each li element and check if the first character of its text is a dash. If it is, the li element will be hidden.
You don't need jQuery.
use String.prototype.trim() on the LI's textContent to remove wrapping whitespaces
use RegExp.prototype.test() to match ^- (starts with dash)
or use String.prototype.startsWith()
or use index String[i] to match a single character at String index
use Element.classList.toggle() to toggle a specific CSS utility class (to hide the element using i.e: display: none;)
Using RegExp.prototype.test()
document.querySelectorAll(".chosen-results li").forEach((li) => {
li.classList.toggle("u-hidden", /^-/.test(li.textContent.trim()));
});
/* Utility classes */
.u-hidden { display: none; }
<ul class="chosen-results">
<li class="active-result" data-option-array-index="4">
-General Discussion
</li>
<li class="active-result" data-option-array-index="0">
Accident Prevention
</li>
</ul>
Using String.prototype.startsWith()
document.querySelectorAll(".chosen-results li").forEach((li) => {
li.classList.toggle("u-hidden", li.textContent.trim().startsWith("-"));
});
/* Utility classes */
.u-hidden { display: none; }
<ul class="chosen-results">
<li class="active-result" data-option-array-index="4">
-General Discussion
</li>
<li class="active-result" data-option-array-index="0">
Accident Prevention
</li>
</ul>
Using String index [i]
document.querySelectorAll(".chosen-results li").forEach((li) => {
li.classList.toggle("u-hidden", li.textContent.trim()[0] === "-");
});
/* Utility classes */
.u-hidden { display: none; }
<ul class="chosen-results">
<li class="active-result" data-option-array-index="4">
-General Discussion
</li>
<li class="active-result" data-option-array-index="0">
Accident Prevention
</li>
</ul>
I have a nested list, as shown below. I'm struggling to find a specific CSS selector that I can use in querySelectorAll() JavaScript function, which will only affect all <li> tags that do NOT contain <ul> tag. So in this case it should be just the lines
<li>foot</li>
<li>leg</li>
<li>tiger</li>
<li>elephant</li>
<li>food</li>
I tried querySelectorAll("ol > li") and some others ways with the :not() selector, but to no success.
querySelectorAll("ol > li ul") is the opposite of what I want, because when I use
console.log(document.getElementById("translation").querySelectorAll("ol > li ul").length) it returns 3.
I need code of the following type console.log(document.getElementById("translation").querySelectorAll(blank).length) which will return 5. I don't know if that's possible, and I can't find it anywhere online.
Another way of looking at it is to let this code of CSS only color items which do not contain other nested lists (so that only points 2-6 will have colored background):
#translation ol > li ul{
background-color: cyan;
}
The entire list:
<div id="translation">
<ol>
<li>
<ul>
<li>parting</li>
<li>parting</li>
<li>parting</li>
<li>separation</li>
<li>separation</li>
<li>separation</li>
<li>farewell</li>
<li>(lateral) branch</li>
<li>fork</li>
<li>offshoot</li>
</ul>
</li>
<li>foot</li>
<li>leg</li>
<li>tiger</li>
<li>elephant</li>
<li>food</li>
<li>
<ul>
<li>branch</li>
<li>parting</li>
<li>disaffiliation</li>
<li>disaffiliation</li>
<li>separation</li>
<li>(lateral) branch</li>
<li>farewell</li>
<li>branch</li>
<li>division</li>
</ul>
</li>
<li>
<ul>
<li>dissociation</li>
<li>disaffiliation</li>
<li>dissociation</li>
</ul>
</li>
</ol>
</div>
You need to check each li is childNodes has ul. For example like this:
const test = [...document.querySelectorAll("ol > li")].filter(
li => ![...li.childNodes].find(child => child.localName === "ul")
);
if you are able to use jQuery then make the :not selector to catch elements that have ul as childs.
something like this:
$("translation").find("ol > li:not(:has(>ul))")
Notice this solution will work for jQuery selectors but not for the Vanilla JS (Vanilla JS doesn't support :has as a seclctor).
With Vanilla JS you might want to do something like this:
const elems = document.getElementById("translation").querySelectorAll('ol > li');
let items = Array.from(elems); // convert to Array type
items.filter(item => { // filter the array
item.querySelectorAll('ul').length == 0
})
This is a build off of my previous question: Select a child of a child
I now have a <ul> within another <ul>. The behavior is an expandable menu. I'm doing this by adding and removing classes. For some reason...on the sub list - it completely removes the <li> elements from the DOM rather than just toggling it's classes. Why would it do that!?
You can see an example below:
$(function() {
// main expansion element
$(".expander").click(function() {
var subShown = $("ul > li", this).hasClass("show");
if (!subShown) {
$(".indented", this).slideDown('100').addClass("show");
$(".caret", this).addClass("reversedCaret");
} else {
$(".indented", this).slideUp('100').removeClass("show");
$(".caret", this).removeClass("reversedCaret");
}
});
// sub expansion element
$(".sub-expander, .caret").click(function() {
var subSelectText = $(".sub-expander").text();
if (subSelectText != "More") {
$(".indented--sub", this).slideUp('100').removeClass("show");
$(".caret", this).removeClass("reversedCaret");
$(".more-or-less").text("More");
} else {
$(".indented--sub", this).slideDown('100').addClass("show");
$(".caret", this).removeClass("reversedCaret");
$(".more-or-less").text("Show Less");
}
});
// stop propagation on the link element within .expander class
$(".indented").click(function(event) {
event.stopPropagation();
});
});
.expander:hover {
cursor: pointer;
}
.sub-expander--indented {
padding: 0 0 0 23px;
}
.sub-caret {
margin-right: 75px;
}
.indented,
.indented--sub {
display: none;
}
.show {
display: block;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.10.2/jquery.min.js"></script>
<div class="expander">
<span class="caret downCaret right visibleCaret">+</span>
<ul>
<li class="category">Item 1
</li>
<li class="indented">Item 2</li>
<li class="indented">Item 3
<ul class="sub-expander indented more" style="padding-top:
0px;">
<li class="indented--sub">Chapter 5</li>
<li class="indented--sub">Chapter 6</li>
<li class="indented--sub">Chapter 7</li>
<span class="sub-caret moreCaret visibleLessCaret right">+</span>
<li class="more-or-less less sub-expander--
indented">More</li>
</ul>
</li>
</ul>
</div>
I'm giving it a separate classname to differentiate from the main section so that they don't show on initial open, so I'm not sure why it is behaving the way it is. It seems like there is a better way to go about this but I don't know what that would be.
UPDATE: was pointed out I did not have valid HTML. Fixed it following this thread. Still broken.
UPDATE #2: It seems like the problem is .text() - so it completely erases everything? I thought it just replaced the text node, and not all of it's children. I tried .html() but it does the same thing. What method do I use to just replace text then?
UPDATE #3 - one answer suggests I needed a more specific selector. I gave the list item a class of .more-or-less but doing that, it doesn't expand at all.
You'd probably want to use a more strict selector.
In your example case you use .sub-expander to select the node of which you want to replace the text. This matches with the ul.sub-expander however.
Since you want it to replace the text of the li.sub-expander the simplest thing you could do would be to use a more specific selector:
$("li.sub-expander").text("Show Less"); or (better) give the node which contains the text you want to replace another classname, id or other identifier to prevent targeting a different element.
I am using socket.io and twitter streaming API.
Now I have to keep the recent three tweets in a list
<ul>
<li></li>
<li></li>
<li></li>
</ul>
My Question is how to do this in Jquery? Whenever there is a new tweet I want to insert it in to first li and move the first li tweet in to second li and so on and remove the 4th tweet.
Use .prepend to insert new element at the beginning of the target element.
Use :gt() to remove the element if length is greater than expected
length.
var count = 0;
$('button').on('click', function() {
var li = '<li>Data New' + count + '</li>';
++count;
$('ul').prepend(li);
if ($('ul li').length > 3) {
$('ul li:gt(2)').remove();
}
})
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<ul>
<li>Data</li>
<li>Data</li>
<li>Data</li>
</ul>
<button>Add</button>
Use .prepend() method in jQuery. This adds HTML element as the first node of the target.
$("ul").prepend("<li>new item</li>");
And as #Kartikeya suggested, remove the last one like:
$("ul > li:last").remove();
I created a vertical menu using unordered list. Within the list, there are subitems that are not displayed until a click event. How do I get a reference to the first ul child element of an li element to change its display style from "none" to ""?
When I click on mnu03, how do I get a reference to mnu031. Right now I'm just adding a "1" to the parent id to create the id of the child, which is kludgy.
I don't want to use jQuery.
The markup follow:
<pre>
<ul>
<li>Item 1</li>
<li>Item 2</li>
<li>Item 3
<ul id="mnu031" style="display:none;" >
<li>Item S1</li>
<li>Item S2</li>
</ul>
</li>
<li>Item 4</li>
<li>Item 5</li>
</ul>
</pre>
In your JavaScript code where you bind to the click:
this.parentElement.querySelector('ul').style.display = 'block';
http://jsfiddle.net/CDXH5/
You have some mismatched quotes in your html, by the way.
assign a class to your li element.
window.onload=function() {
var obj=document.getElementsByClassName('x');
for(var i=0;i<obj.length;i++)
{
obj[i].addEventListener("click", function() {
for(var i=0;i< this.childElementCount ;i++ )
{
// write ur code here this.children[i] is your reference
}
});
}
}
Using CSS sibling selectors for styling only the first of it's class. The following selects only the first ul under an li
li > ul {}
There are other sibling type selectors that may you want to try out.
The descendant selector
The adjacent sibling combinator
The general sibling combinator.
The Descendant Selector:
This is styling any list items that are anywhere underneath an unordered list.
ul li{}
Adjacent Sibling Combinator:
p + p { font-size: smaller; } /* Selects all paragraphs that directly follow another paragraph */
The child combinator selector: Selecting tags that are strictly direct children of <p> tags in your markup.
p > img
Not sure if this is what you're looking for but it's what I would use if it must be JS free.
css-tricks.com