Issue with adding UL markup for LI - javascript

This sounds simple, and it should be, but it doesn't seem to be so cut and dry...
I have a list of li elements..
<li>Text here</li>
<li>Text here</li>
<li>Text here</li>
What I want to do is find the 1st one, add <ul> before it. Find the last one, add </ul>
It sounds simple but stay with me...
First I tried this:
$('li').each(function(i,obj) {
var x = $(this);
if(x.prev().prop('tagName')!=='LI') x.before('<ul>')
if(x.next().prop('tagName')!=='LI') x.after('</ul>')
});
Which evolved into this:
$('li').each(function(i,obj) {
var x = $(this);
$.fn.outerHTML = function(){
var x = $(this);
x.wrap('<p/>')
var html = x.parent().html();
x.unwrap();
return(html);
}
alert(x.outerHTML());
if(x.prev().prop('tagName')!=='LI') x.html('<ul>'+x.outerHTML())
if(x.next().prop('tagName')!=='LI') x.html(x.outerHTML()+'</ul>')
});
The 1st code places an empty UL before the 1st LI (closing tag and all)
The 2nd wraps only the 1st LI.
It goes down the list 1, 2, 3 and seems to report back properly... something (possibly jQuery) seems to be altering my code somewhere along the way. Can anyone shed some insight here?
Fiddle to fiddle with: http://jsfiddle.net/yr67N/
Update:
As you can see from the code, the lis must be grouped together. wrapAll won't work here.

Just tried this on your fiddle and it appears to work:
var collectedLi = [];
$('li').each(function(){
collectedLi.push(this);
if(!$(this).next().is('li')){
$(collectedLi).wrapAll('<ul/>');
collectedLi = []
}
});
For every li it will check if the next element is also an li, if not it will wrap the current collection in a ul and then empty the collection to continue the loop.
Just realized that the above code will also wrap already wrapped li tags, here is a solution that will handle this:
var collectedLi = [];
$('li').each(function(){
collectedLi.push(this);
if(!$(this).next().is('li')){
if(!$(this).parent().is('ul')){
$(collectedLi).wrapAll('<ul/>');
}
collectedLi = []
}
});

How about:
$('li').wrapAll('<ul/>');
Fiddle

var ul,
tname;
$('li').each(function(i, el){
tname = $(el).prev().prop('tagName');
if(String(tname) !== 'UL'){
ul = $('<ul></ul>');
$(el).before(ul[0]);
}
$(this).appendTo(ul);
});
fiddle

Related

Hide same elements in a list

I have a problem I want to solve with jQuery. In a list, I want to check if two items have the same text, and if so I want to delete the second one.
I am not really sure how to go about it.
The markup is simple, kinda like this
<ul>
<li>Text1</li>
<li>Text2</li>
<li>Text1</li>
<li>Text3</li>
<li>Text3</li>
<li>Text4</li>
<ul>
I cannot use an active/inactive class because this list is dynamic and I don't know in advance how it's going to be populated.
Any idea?
$.inArray for a tmp array would work.
$(document).ready(function(){
var tmparr = [];
$('.list li').each(function(i,item){
if($.inArray($(this).text(), tmparr) >= 0){
$(this).remove();
}else{
tmparr.push($(this).text());
}
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="list">
<li>Text1</li>
<li>Text2</li>
<li>Text1</li>
<li>Text3</li>
<li>Text3</li>
<li>Text4</li>
<ul>
You can achieve this e.g. like this:
var unique = {};
$('li').each(function() {
var txt = $(this).text();
if (unique[txt])
$(this).remove();
else
unique[txt] = true;
});
Fiddle
As explanation: unique is initialized as object. While each() iterates over all li elements, the if (unique[txt]) is true in case it was previously set to true for the text of the li currently processed. In this case the current li will be removed. If not, unique[txt] for the text of the current li is set to true and added to unique. As it might not be clear what unique finally contains: { Text1=true, Text2=true, Text3=true, Text4=true }
You will need to iterate over your li elements and store their text in an array. If the text for the ith element is already in the array, skip it. Once you have an array of unique text strings, remove all li elements and generate new ones from the information in your array.
http://jsfiddle.net/k255o52e/1/
$('ul li').each(function () {
var txt = $(this).text();
// finds all LI that contain the same text
// excludes the first element
var $li = $('li:contains("' + txt + '"):not(:first)');
// and removes the other
$li.remove();
})
UPDATE:
$('ul li').each(function () {
var txt = $(this).text();
var $li = $('li:contains("' + txt + '"):not(:first)').filter(function(index)
{
return $(this).text() === txt;
});
$li.remove();
})

jQuery DOM - Inserting multiple nodes in li (menu)

I know there are dozens of similar topics but I am so dumb I can't learn anything from it.
Other words: My code is just mean and doesn't work with any fixes published online. ;)
My HTML:
<ul id="main_menu">
<li class="menu-item">Link 1</li>
<li class="menu-item">Link 2</li>
<li class="menu-item">Link 3</li>
<li class="menu-item">Link 4</li>
</ul>
and how the LI should look after JS does its magic:
...
<span data-title="Link 1">Link 1</span>
...
JS/JQ mission:
add class="roll-link" to every A
add SPAN right after A tag
add data-title="xxx" attribute to SPAN with A value (text exactly the same as the A)
close SPAN tag before A closing tag
My JS try:
var menuLis = document.querySelectorAll("ul.main_menu li"); //It's an Array right?
for(var i=0; i<menuLis.length; i++) {
this.nextChild.setAttribute('class', 'rollink');
var span = document.createElement('span');
this.nextChild.nextSibling.insertBefore(span); //Auto-closing </span> may be an issue...
span.setAttribute('data-title', hrefvalue[i]); //but how to get value?
}
It may be total crap but I have completely no experience in JS/JQ, only had few hours of basic training online...
Thanks for reading and even bigger thanks for trying to help.
Greets!
it should be as simple using jQuery(because you tagged it with jQuery)
jQuery(function ($) {
$('#main_menu li a').addClass('roll-link').wrapInner(function () {
return $('<span />', {
'data-title': $.trim($(this).html())
});
})
})
Demo: Fiddle
See
selectors
addClass()
wrapInner()
dom ready
To make your code work, first the main_menu is an id, not a class so you need to use id selector, then try
var as = document.querySelectorAll("#main_menu li a");
for (var i = 0; i < as.length; i++) {
as[i].className = 'rollink';
var span = document.createElement('span');
span.setAttribute('data-title', as[i].innerHTML);
span.appendChild(as[i].firstChild);
as[i].appendChild(span)
}
Demo: Fiddle
$('#main_menu > li > a').each(function () {
var text = $(this).addClass('roll-link').contents().first();
text.wrap($('<span>').attr('data-title', text.text()));
});
DEMO: http://jsfiddle.net/Bw723/
Here is your solution with pure Javascript.
//get the li elements
var menuLis = document.getElementById("main_menu").getElementsByTagName('li');
for(var i=0; i<menuLis.length; i++) {
menuLis[i].firstChild.setAttribute('class', 'rollink');
var span = document.createElement('span');
span.setAttribute('data-title', menuLis[i].innerHTML);
//If you want to get href of a then use this one.
//span.setAttribute('data-title', menuLis[i].href);
//appending the span into a
menuLis[i].firstChild.appendChild(span);
}
DEMO

Javascript efficient approach for changing inner dom elements of a list item

I have a unordered list with 12 list items inside it
<ul class="rb-grid" id="list">
<li class="view view-fifth">
<div class="mask">
<h2>Article Name</h2>
<p>Brief</p>
Read More
</div>
</li>
...
...
</ul>
Now what i want is that on page load i have to change the content of these h2 and p tags, now while i can do this by hardcoding every list item, but can anyone tell me a better way to make all changes at once by using javascript or jquery anything....
Now i found something like this in dojo , this will make clear what i want actually -
var items = registry.byId("list").getChildren();
array.forEach(items, function(item, idx) {
item.onClick = function(evt) {
};
});
I want to do some such thing to change the contents of the h2 and the p tags inside every list items
Try this: (jquery)
var lis = $('.rb-grid').children('li');
for(var i = 0; i < lis.length : i++){
$(lis).eq(i).find('p').html("change to something");
$(lis).eq(i).find('h2').html("change to something");
}
js
var x =$('.rb-grid').children('li');
x.find('p').html('change to something');
x.find('h2').html('change to something');
A non jquery way:
var ee = document.getElementById('list').getElementsByTagName('li');
for(i=0; i<ee.length; i++) {
ee[i].getElementsByTagName('h2')[0].textContent = "hello world";
ee[i].getElementsByTagName('p')[0].textContent = "article 2";
}
EDIT: It seems IE previous to IE9 does not have textContent and should use innerText instead. Thanks Mr_Green!
Here for comparison is a more idiomatic jQuery version of Mr_Green's answer:
$('.rb-grid').children('li').each( function( i, element ) {
var $element = $(element);
$element.find('p').html("change to something");
$element.find('h2').html("change to something");
});
OTOH, you may not even need the loop, depending on what you're doing. If you just want to change all the relevant nested p and h2 elements to the same value, then Tushar Gupta's answer is a simpler way to do it.

How to find number of <ul> inside each div

I have a large file of this form [similar div's throughout]. I want to be able to select a div, find the number of ul's in it and traverse through each of them to get value of each li in it.
<div class="experiment">
<div class="experiment-number">5</div>
<ul class="data-values">
<li><div></div> 14</li>
<li><div></div> 15</li>
</ul>
<ul class="data-values">
<li><div></div> 16</li>
</ul>
</div>
I have tried looping through all experiment divs, then select the uls, but it selects all the ul in the page, not only the ones under current div.
$('experiment ul').eq('$i');
Your HTML is currently incorrect, since you're simply starting new <div> and <ul> elements rather than closing the existing ones. Ignoring that because it's trivial to fix, we'll move on to the real issue.
You need to select all of the <div class="experiment"> elements, then iterate through them. To do that you can use the .each() function. It might look something like this:
var experiments = $('.experiment'); // all of them
experiments.each(function(i, val) { // will iterate over that list, one at a time
var experiment = $(this); // this will be the specific div for this iteration
console.log("Experiment: " + experiment.find('.experiment-number').text());
// outputs the experiment number
console.log("Experiment ULs: " + experiment.find('ul').length);
// number of <ul> elements in this <div>
var total = 0;
experiment.find('ul.data-values li').each(function() {
total += parseInt($(this).text(), 10);
});
console.log("Experiment total: " + total);
// outputs the total of the <li> elements text values
});
Take a look at this jsFiddle demo.
to get all the ul inside div.experiment
var ul = $('.experiment').find('ul');
and to get all li elements inside each ul found above
ul.each(function(list) {
var li = $(list).find('li');
});
$('.experiment').each(function() {
var cnt = $(this).children('ul').length;
$(this).find('.experiment-number').text(cnt);
});
First of all you need to work out the correct selector for each DIV.
The selector you want is:
".experiment"
Notice the . to denote a class selector.
This will allow you access to each DIV element. If you then want to loop though each of these, you can do so like this:
$(".experiment").each(function(){
var div = $(this);
var elementsInThisDiv = div.find("ul");
//you now have a list of all UL elements in the current DIV only
var numberOfElements = elementsInThisDiv.length;
//you now have a count of UL elements belonging to this DIV only
//you can loop the UL elements here
$(elementsInThisDiv).each(function(){
var ul = $(this);
//do something with the UL element
//like get the LI elements...
var liElements = ul.find("li");
});
});
IMPORTANT: There is also an error with your HTML, you need to close your <ul> elements correctly using </ul>

Whether particular li with a specific text exists inside a ul using JQUERY

I have a code
like
<ul id="uploadedfiles">
<li>
A_001
</li>
<li>
B_001
</li>
</ul>
Now i want to insert a new li but i want to check that something that whether a li with a text say A_ exist in that ul. If it exists than remove the older and add the new li.
Say if i add C_001 it is added with no issue
But if i add A_002 then it replace the A_001 with A_002.
Please provide the code for the same if possible.
Any help is appreciated!
Added:
The real data in li have text like control20_a.jpg , control21_b.jpg .....
Then when adding a new li say control20_c.jpg the code must replace control20_a.jpg. But add a new li if it does not exists
This is probably not very idiomatic jQuery, but it seems to do the job.
Working Example
var add = function(entry) {
var match = $('#uploadedfiles li:contains(' + entry.slice(0, entry.indexOf('_')) + ')');
if (match.length > 0) {
match.text(entry);
} else {
$('#uploadedfiles').append($('<li>' + entry + '</li>'));
}
}
I would add a class to the li (like <li class="a"> and <li class="b">
When adding the new LI i would strip the first char of the name and find the LI
If no li, I would create it else change the innerHTML for the new one.
Good luck
UPDATE:
if the elements are from 001 to 002 etc you could do
$("ul li").each(function() {
var firstChar = $(this).text().substring(0,1);
var removeElms = $("ul li:contains('"+firstChar+"'):not(:last)");
removeElms.remove();
});

Categories

Resources