I have a bulletted list like this:
<ol>
<li>Point 1</li>
<li>Point 2</li>
<li>Point 3 has sub-points
<ul>
<li>Sub-point about something</li>
<li>Sub-point about something else</li>
</ul>
</li>
</ol>
I am transliterating from one writing script to another writing script, so I have to run something against the text in each tag. Here is what my jQuery looks like:
$("li").each(function() {
text = dev2latin($(this).text());
}
It makes it look like this:
Point 1
Point 2
Point 3 has sub-points Sub-point about something
Sub-point about something else
I have tried several iterations of jQuery selectors including ol>li, etc, but none of them give the desired result. Thoughts?
The problem is calling .text() in the parent li will return the text content of the child li also
$("li").contents().each(function () {
if (this.nodeType == 3 && this.nodeValue.trim()) {
this.nodeValue = dev2latin(this.nodeValue)
}
})
Demo: Fiddle
You can fetch text nodes using .contents(), then you can .filter() them and perform desired operation.
$(document).ready(function() {
$("li")
.contents()
.filter(function() {
return this.nodeType == 3;
}) //Filter text nodes
.each(function() {
this.nodeValue = dev2latin(this.nodeValue); //You can also textContent
});
});
Here is an example:
$(document).ready(function() {
$("li").contents().filter(function() {
return this.nodeType == 3;
}).each(function() {
this.textContent = this.textContent + 'Updated';
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ol>
<li>Point 1</li>
<li>Point 2</li>
<li>Point 3 has sub-points
<ul>
<li>Sub-point about something</li>
<li>Sub-point about something else</li>
</ul>
</li>
</ol>
$('ol > li').each(function(){ console.log($(this)[0].childNodes[0]); });
$('ul > li').each(function(){ console.log($(this)[0].childNodes[0]); });
Try this way.
Related
What I'm trying to do is essentially go through uls which are organized like
<ul class="some-ul">
<li class="some-li"></li>
<li></li>
<li></li>
<li class="some-li"></li>
</ul>
<ul class="some-ul">
<li class="some-li"></li>
<li></li>
<li></li>
<li></li>
</ul>
<ul class="some-ul">
<li class="some-li"></li>
<li class="some-li"></li>
<li class="some-li"></li>
<li class="some-li"></li>
</ul>
and do something with the lis of class some-li and something else with the lis that don't have that class. So, it would be equivalent to
$('ul.some-class li.some-class').each(function() {
// do something
});
$('ul.some-class li:not(.some-class)').each(function() {
// do something else
});
except I want to do it like
$('ul.some-class').each(function() {
// loop through the list elements of this list
});
but I don't know how to construct that inner loop. Is this possible, and if so, what tool should I using?
Within .each, this will be the current element of the iteration. You can then use $(this).find() to find elements within it:
$('ul.some-ul').each(function(i, ul) {
$(ul).find("li").each(function(j, li) {
// Now you can use $(ul) and $(li) to refer to the list and item
if ($(li).hasClass('some-li')) {
...
}
});
});
You can use hasClass and a CSS selector to get all immediate children (The <li>s).
$('ul.some-class > li').each(function() {
if ($(this).hasClass('some-class')) {
//Do something
} else {
//Do something else
}
});
Loop through all the <li> and use hasClass() to see if they fit the class you want or not and react accordingly
$('.some-ul').children().each(function(){
// "this" is current li
if ( $(this).hasClass('some-li') ){
$(this).doSomeClassThing();
} else {
$(this).doNoClassThing();
}
});
One pass through and you are done
The callback of the each call gets the index and the element as arguments.
This way you can
$('ul.some-class').each(function(i, elt) {
$(elt, 'li.some-class').each ...
});
https://api.jquery.com/jquery.each/
does anybody know how to reiterate through only the first 5 elements using jQuery's each?
$(".kltat").each(function() {
// Only do it for the first 5 elements of .kltat class
}
From the documentation:
We can break the $.each() loop at a particular iteration by making the callback function return false.
Furthermore, the same documentation says of the callback you give to .each:
In the case of an array, the callback is passed an array index and a corresponding array value each time.
So try something like this:
$(".kltat").each(function(index, element) {
// do something
// ...
return index < 4;
});
So after you execute the loop on the fifth time (index will equal 4), the loop will stop. Note that using this n-1 logic is needed because you execute the body of the loop before you evaluate the breaking condition.
$(".kltat").each(function(index, element) {
$(element).css('color', 'red');
return index < 4;
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li class="kltat">Item 1</li>
<li class="kltat">Item 2</li>
<li class="kltat">Item 3</li>
<li class="kltat">Item 4</li>
<li class="kltat">Item 5</li>
<li class="kltat">Item 6</li>
<li class="kltat">Item 7</li>
</ul>
You can implement a counter such as this:
var counter = 1;
$(".kltat").each(function() {
// Only do it for the first 5 elements of .kltat class
if (counter==5) {
return false;
} else {
counter++;
}
}
or something of this sort.
How about using .filter():
$(".kltat").filter(function (i) { return i < 5; })
.each(function () {
// ...
});
$(".kltat").slice(0,5).each(function() {
// Only do it for the first 5 elements of .kltat class
})
And without jquery:
[].slice.call(document.querySelectorAll('.kltat')).slice(0,5).forEach(function (element) {
doStuff(element)
})
How can i select elements which have more than a number of children?
I have something like this:
<ul>
<li>foo<li>
<li>foo<li>
<li>foo<li>
</ul>
<ul>
<li>foo<li>
<li>foo<li>
</ul>
<ul>
<li>foo<li>
<li>foo<li>
<li>foo<li>
</ul>
and i am using somthing like this right now:
$('ul').each(function() {
if ($(this).children().length > 2) {
// do something
}
});
I want to know if there is a better way for selecting by number of children?
or any better way to do this?
There is at least a shorter way
$('ul:has(li:eq(2))')
For immediate children only, if that's an issue, you can do
$('ul:has( > li:eq(2))')
selects any UL with 3 or more children (eq is zero based)
FIDDLE
This should work:
var listsWithMoreChildren = $('ul').filter(function( index ) {
return $(this).children().length > 2;
});
listsWithMoreChildren.css('background-color', '#ff0');
For more information on the filter function, please read the documentation. http://api.jquery.com/filter/
$('ul').each(function() {
if ($(this).find('li').length > 2) {
alert('hi');
}
});
Use find to count number of children available for ul.
Demo:
http://jsfiddle.net/7GX9F/1/
var i = 0;
$('ul').each(function (index, ele) {
if ($(this).children().length > 0) i++;
})
alert('Total UL with children LI : ' + i);
FIDDLE
http://jsfiddle.net/nraina/GckZL/
How can I traverse an ordered list and return the text if I have a scenario where the user can click on a li element like Cat 1-2 and it returns all of the parent li's text into a string or an array. If an array I can reverse the sort but eventually I need it to be a string.
Example:
<ul>
<li>Cat 1
<ul>
<li>Cat 1-1
<ul>
<li>Cat 1-2</li>
</ul>
</li>
</ul>
</li>
<li>Cat 2
<ul>
<li>Cat 2-1
<ul>
<li>Cat 2-2</li>
</ul>
</li>
</ul>
</li>
</ul>
if clicked on Cat 1-2 the desired result would be:
str = "Cat 1/Cat 1-1/Cat 1-2";
if clicked on Cat 2-1 the desired result would be:
str = "Cat 2/Cat 2-1";
What I would like to have is checkboxes on this where I could join all the selections into a string hierarchy like:
str = "Cat 1/Cat 1-1/Cat 1-2|Cat 2/Cat 2-1";
Here; I'll show a down and dirty method to get you rolling, then you can find a better way (maybe using textContent)...
$('li').click(function(e){
var parents = $(this).add($(this).parents('li'))
.map(function(){
return $(this).clone().children().remove().end()
.text().replace(/\r|\n|^\s+|\s+$/g,'');
})
.toArray().join('/');
alert(parents);
e.stopPropagation();
});
I don't know if this is any more efficient than Brad's method, but I started working on this earlier and it bugged me until I had it finished.
jsFiddle example
var ary = [];
$('li').click(function (e) {
ary.push($.trim($(this).clone()
.children()
.remove()
.end()
.text()));
if ($(this).parents('ul').parent('li').length == 0) {
console.log(ary.reverse().join('/'));
ary = [];
}
});
<ul>
<li>Menu 1
<ul>
<li>submenu 1</li>
<li>submenu 2
<ul>
submenu 3
<li>submenu 4</li>
</ul>
</li>
</ul> Menu 2
<ul>
<li>submenu 1</li>
<li>submenu 2
<ul>
submenu 3
<li>submenu 4</li>
</ul>
</li>
</ul>
<li>
</ul>
script:
if(!Array.indexOf){
Array.prototype.indexOf = function(obj){
for(var i=0; i<this.length; i++){
if(this[i]==obj){
return i;
}
}
return -1;
}
}
function categoryAdd(id) {
var ids = new String($.cookie('expanded')).split(',');
if (ids.indexOf(id) == -1){
ids.push(id);
$.cookie('expanded', ids.join(','), {path: '/'});
}
}
function categoryRemove(id) {
var ids = new String($.cookie('expanded')).split(',');
// bug #7654 fixed
while (ids.indexOf(id) != -1) {
ids.splice(ids.indexOf(id), 1);
}
$.cookie('expanded', ids.join(','), {path: '/'});
}
$('.category_button').click(function(e){
var change = '<?= $change; ?>';
var current = $(this).attr('current');
if(change == 'on')
{
var ids = new String($.cookie('expanded')).split(',');
var exceptions = ''
for(var i = 0; i < ids.length; i++)
{
id = ids[i];
current = $('category_' + ids[i]).attr('current');
if($('category_' + ids[i]).css('display') != 'none')
{
if(id != $(this).attr('id').split('-')[1] && $(this).parent().parent().attr('id').split('-')[1] == 'undefined')
{
hideAll(id, '256');
}
}
}
}
function hideAll(id, except)
{
if(id == except){return;}
var button = $('#image-'+ id);
button.attr('src', 'catalog/view/theme/default/image/btn-expand.png');
$('#category_' + id).hide(200);
}
function showMenu(id)
{
var button = $('#image-'+ id);
button.attr('src', 'catalog/view/theme/default/image/btn-collapse.png');
$('#category_' + id).show(200);
}
function toggleMenu(e,id, current)
{
if(current == '1')
{
e.preventDefault()
var button = $('#image-'+ id);
if ($('#category_'+id).css('display') == 'none'){
button.attr('src', 'catalog/view/theme/default/image/btn-collapse.png');
categoryAdd(id);
} else {
button.attr('src', 'catalog/view/theme/default/image/btn-expand.png');
categoryRemove(id);
}
$('#category_'+id).toggle(200);
}
else
{
var button = $('#image-'+ id);
if ($('#category_'+id).css('display') == 'none'){
categoryAdd(id);
} else {
categoryRemove(id);
}
}
}
How can I make a menu where i click on some item and it opens, and others OPENED menu <ul> tags will close e.g. display: none, but also the parent menu need to not to be closed, only the menu in the same level, but not the parent, and also the brother menu of the parent, but not his parent, i think you understand what i am talking about..i really don't have an idea how to do that, what i've made before its working bad...maybe its some kind of recursion here?, but how?
any ideas?
UPDATE:
So now here we have 2 functions that are adding or deleting from the cookies the lists of the menu that has been opened/closed,
for example in the cookies we save menus with id: 100, 200, 300, 250, 160
so how can i make that in a loop closing all the menus with that ids, but not the current menu that we are clicking now, and not his parent...
This can be done using a javascript/jquery plugin you will need to just do some googling to find one. You will just need to adjust the plugin according to your specifications.Once you find plugin and try to work with that, then you could come back here if you need help. It shows more effort when you have some solid code to show you have exhausted your talents. Study some of these I think you want an accordion menu if I understand correctly. Jquery
You would probably be better off googling some different CSS menus and what not. However given your basic HTML there (provided its cleaned up, your missing a closing li tag or two) you could use the following:
jsFiddle
Script [Updated to show how i support the sub tags on the fiddle as well, keep in mind, you can edit this code to do as you please, ffor more information on how each part works, please see jQuery API]
$("ul > li > ul").hide();
$("ul > li").click(function(e) {
e.stopPropagation();
$(this).children().toggle(function(e) {
if (!$(this).is(":visible")) {
$(this).find("ul").hide();
$(this).find("sub").show();
};
});
$(this).siblings().each(function(i) {
if ($(this).children("ul").length > 0) {
if ($(this).children("ul").css("display").toLowerCase() == "block") {
$(this).children().toggle(function(e) {
if (!$(this).is(":visible")) {
$(this).find("ul").hide();
$(this).find("sub").show();
};
});
}
}
});
});
$("ul > li").each(function(i) {
if ($(this).children("ul").length > 0) {
$(this).css("cursor", "pointer").prepend($("<sub />").text("[has submenu]"));
}
else {
$(this).css("cursor", "default");
};
});
Clean HTML
<ul>
<li>Menu 1
<ul>
<li>submenu 1</li>
<li>submenu 2
<ul>
<li>submenu 3</li>
<li>submenu 4</li>
</ul>
</li>
</ul>
</li>
<li>Menu 2
<ul>
<li>submenu 1</li>
<li>submenu 2
<ul>
<li>submenu 3</li>
<li>submenu 4
<ul>
<li>subsubmenu 1</li>
<li>subsubmenu 2</li>
</ul>
</li>
</ul>
</li>
</ul>
<li>
</ul>