I am trying to append a list element dynamically to already existing list.
I've a list in the form,
<ul id="test">
<li class="testField">YYAAHOOOOOO<li>
</ul>
I am trying to add an extra item to this list using jQuery append or after...
What I did was:
$(".testField").after("<li class='testField'>TEST MESSENGER</li>");
Used after function as append did not work, the after function works fine first time as there is only one element with the class name testField, but as the list grows, the after function will add the list items to all elements present,
To make it clear, on first trial I will get an output:
<ul id="test">
<li class="testField">YYAAHOOOOOO<li>
<li class='testField'>TEST MESSENGER</li>
</ul>
If I try the to add another element now for example <li class='testField'>GOOGLE</li>, the output will be like:
<ul id="test">
<li class="testField">YYAAHOOOOOO<li>
<li class='testField'>GOOGLE</li>
<li class='testField'>TEST MESSENGER</li>
<li class='testField'>GOOGLE</li>
</ul>
I thought about using ids, but I am trying to have an option to remove elements from the list too... So if I try to append to an undefined id, it will return error. Is there anyway to find the first element inside a list and append the element to that first one?
Try:
$(".testField:first").after("<li class='testField'>TEST MESSENGER</li>");
this will make sure that you are appending after the first element only
Alternatively, you could do this without jQuery:
var li = document.createElement('li'); // Create a List item.
li.setAttribute("class", "testfield"); // Set the li's class
li.addChild(document.createTextNode("Your Text Here!")); // Set the li's text
document.getElementById("test").addChild(li); // Append the li to the list
It's slightly more code, yes, but it's pretty much what jQuery does under the hood. (And faster, too)
If you want to add the new ul after the first li already in the list, replace the last line with:
var ul = document.getElementById("test");
if(ul.children.length > 1){ // If the list has 2 or more children (li's)
ul.insertBefore(li, ul.children[1]); // Insert the new item before the second item in the list.
}else{
document.getElementById("test").addChild(li);
}
Now, why am I posting a answer that requires more code?
Anything that can be done in jQuery can be done in native JS. I think it's good to have multiple different answers available on SO, especially if they use different techniques to do the same thing. That way, users can chose for themselves: short'n easy (jQuery), or if they don't want to use the library, native code.
Related
I am currently writing a Nightwatch test to select a new document from a list. And I will need to be able to select the next in the list. Is there a way to manually override the child number that needs selecting?
For example the current selector being used is :
<ul class="dv-packdocs">
<li class="dv-packdoc"<div class="icon-todo"></li>
<li class="dv-packdoc"<div class="icon-todo"></li>
<li class="dv-packdoc"<div class="icon-todo"></li>
<li class="dv-packdoc"<div class="icon-todo"></li>
</ul>
and the test would be something like :
viewer.selectNewDocument([2])
would this select the second child under the ul?
Or would I have to specify each child element?
If I understand correctly, you are trying to dynamically find the appropriate child element (li) from a dynamical length list (ul, where the list is populated based on user input, or other site actions). Correct?
I see two scenarios with two different approaches:
1. You have a set/fixed condition (way of identifying your target element): for example, in your list, the second li would be targeted by the below command.
viewer.selectNewDocument('ul.dv-packdocs li:nth-child(2)') (considering you are passing a complete selector to the selectNewDocument function)
, or
viewer.selectNewDocument(2), passing a number & form the selector inside the command (if you care for aesthetics):
selectNewDocument: function(index) {
this.api.perform((done) => {
// Click the second document in the list:
let selector = `ul.dv-packdocs li:nth-child(${index})`;
this.api.click(selector);
done();
});
return this;
},
Alternatively, if you would want the last document added, then you would have to issue a elements call on the ul to retrieve the length of the list, then use that in the same way to determine which li you have to click: viewer.selectNewDocument('ul.dv-packdocs li:nth-child('+length+')') (where length is the result of your elements call).
2. You don't have a fixed condition (I'll fill this up if the first part doesn't cover it, or later today, kinda slammed after the holidays)
Hope it's what you were looking for! Cheers!
$('#mainlist').last().hide().fadeIn(200);
Why is this hiding, and then fading in all the items in the list instead of just the last one?
Edit: The section of HTML:
<div id="mainbox">
<ul id = "mainlist">
</ul>
</div>
My js appends to the ul with a li, and then it runs the first code shown above.
It's because there's only one element in the list returned by $("#mainlist"). You're selecting the last #mainlist which is your ul.
The .last() method selects the last element in a list of DOM elements, not the last child of the elements selected.
From the jQuery docs:
Given a jQuery object that represents a set of DOM elements, the
.last() method constructs a new jQuery object from the last element in
that set.
You want something like $('#mainlist li').last().hide().fadeIn(200); instead.
It's because your #mainlist element has another child/wrapping <ul> before the list items (so it's hiding the wrapping <ul>, thus all the elements). Maybe try be more specific with your selector
$("#mainlist li").last().hide().fadeIn(200);
EDIT By the way, this assumes your <ul> is filled with <li> tags.
I have a regular html ordered list:
<nav id="global_nav">
<ol class="menu">
<li id="Section1">Section1</li>
<li id="Section2">Section2
<ol>
<li id="subsection1">Subsection1</li>
<li id="subsection2">Subsection2</li>
<li id="subsection3">Subsection3</li>
</ol>
</li>
<li id="Section3" >Item3</li>
</ol>
</nav>
and I made a small html form too:
<form>
<label for="nuevo">Insert</label>
<input type="text" id="nuevo">
<label for="despues">After the section</label>
<input type="text" id="despues">
<input type="button" id="btn" value="Insert">
</form>
The point is to be able to populate the list dinamically using jQuery. For example, if in the text field 1 I type 'Section4' and in the text field 2 I type 'Section3', the function will add a new <li>element with the text 'Section4' right after the already existing 'Section3'.
I have done this, and it kind of works ok:
$("#btn").click(function(){
var nuevo=$('#nuevo').val();
//var despues=$('#despues').val();
var nl = $('<li></li>').text(nuevo).attr('id', nuevo ).slideDown();
$(".menu").append(nl);
But as you see, I have commented out the line grabbing the value of the second text field, because I cannot understand how should I make the reference to the sibling item that will determine the placement of the new item. For instance, if the first item I attach is "Section7" and it goes appended to the very bottom of the list, how can I attach a "Section6" later on right before "Section7"?
What jQuery functions would you say that I need to use in order to get going with this? Up to now I only knew a bit of pure javascript. I am trying to understand all the cool things with jQuery but in this case I am finding in the docs a lot of functions that are apparently very similar, so I am quite confused.
Thanks!
Here's a fiddle for the same. I hope this helps.
http://jsfiddle.net/zy1f7ohc/5/
$("#btn").click(function(){
var nuevo=$('#nuevo').val();
var despues=$('#despues').val();
$('<li></li>').text(nuevo).attr('id', nuevo).insertAfter("#"+despues);
});
In this line:
$(".menu").append(nl);
You are always adding your new list item to the very end of the the whole menu.
Try this instead for inserting it after the value for "nuevo" (after uncommenting the "despues" line):
$("#" + despues).after(nl);
For before, assume you have another text input with id "antes":
$("#" + antes).before(nl);
In these examples, we're adding the element immediately next to (or before) the item you specified by id rather than appending it to the end of the parent element.
I tried to simplify your code a little bit. Type in the following snippet a text and a section (for example "B" to append something after the list item "B"):
$("button").click(function(){
var arr = [];
//Store every value from each input (two values)
$("input").each(function(){
arr.push($(this).val());
});
//loop through every list item
$("li").each(function(){
//create a new node with the text stored in the array on the first index (0)
var newli = document.createElement("li");
newli.appendChild(document.createTextNode(arr[0]));
//If the html fits the second index in the array (means the value from the second input) we append the node after that item
($(this).html() === arr[1]) ? $(this).append(newli) : null;
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ol>
<li>1</li>
<ol>
<li>A</li>
<li>B</li>
</ol>
<li>2</li>
</ol>
<input>Text</input>
<input>Section</input>
<button>Send</button>
What we do here is creating an array to store the two input values. After that we loop through every "li" element to find the one we're searching for. If the html fits, we can append a additional node after the particular list item.
What's interesting here is the node creation. You are able to find a complete reference here:
http://www.w3schools.com/js/js_htmldom_nodes.asp
Also check out this function: http://api.jquery.com/each/
Your main issue has been explained in other answers.
However, I'd do it differently. I'd use select instead of input, because the user experience would be terrible when typing elements into text box like that (while it can be easily automated with select).
That way it will be much easier to use and far more accessible for the user.
SIDE NOTE:
Better make sure that the inputed id does not exist in the DOM already. You definitely don't want to have multiple elements with the same id.
function selectSet(){
var d = $('#despues').empty();
$('.menu li').each(function(){
var txt = $.trim($($(this).contents()[0]).text());
d.append('<option value="'+this.id+'">'+txt+'</option>');
});
// set last option as selected by default:
$('option:last', d).prop('selected', true);
}
// set select box dynamically:
selectSet();
$("#btn").click(function(){
var nuevo = $('#nuevo').val(),
despues = $('#despues').val(),
// make unique id (simple version):
id = nuevo + ($('.menu li').length + 1);
// hide and slideDown the new element, so that you can see the animation:
$('<li id="'+id+'">'+nuevo+'</li>').insertAfter("#"+despues).hide().slideDown();
// update select box:
selectSet();
});
JSFiddle
I have a list of links, one has the class active.
On my next button click id like to remove the class from the current element and add it to the next only I cant seem to get it to add?
Ive made a fiddle to hopefully explain my problem, any help would be great, thanks
http://jsfiddle.net/h6D4k/
$('.next').click(function(){
$('ul.pagination').find('a.active').removeClass('active');
$('ul.pagination').find('a.active').next('a').addClass('active');
return false;
});
One of the jQuery most usable conveniencies is that its methods are (usually) chainable - in other words, they return the very object they are called from. So you can simply write this:
$('ul.pagination').find('a.active').removeClass('active').closest('li')
.next('li').find('a').addClass('active');
... as it's <li> elements that should be 'nexted', not <a> ones. But in fact, you shouldn't probably discard 'active' altogether if it's the last element in question:
var $a = $('ul.pagination').find('a.active'),
$li = $a.closest('li'),
$nextLi = $li.next('li');
if ($nextLi.length) {
$a.removeClass('active');
$nextLi.find('a').addClass('active');
}
This is actually what you want based on your html structure in you fiddle. http://jsfiddle.net/h6D4k/1/
$('ul.pagination').find('a.active').removeClass('active').parent()
.next().find('a').addClass('active');
Because once you've done this...
$('ul.pagination').find('a.active').removeClass('active');
There is no more a.active - the active classname has been removed from that element. So repeating the same selector...
$('ul.pagination').find('a.active')//...
... will select nothing.
Chain it all together instead.
$('ul.pagination').find('a.active').removeClass('active').next('a').addClass('active');
You have a second problem. According to the jQuery API for next(), it will:
Get the immediately following sibling of each element in the set of matched elements. If a selector is provided, it retrieves the next sibling only if it matches that selector.
You're not trying to get the following sibling:
<ul class="pagination">
<li><a class="one active" href="#">X</a></li>
<li><a class="two" href="#">X</a></li>
<li><a class="three" href="#">X</a></li>
</ul>
Next
Prev
You're trying to get the next <a> in the whole document. That's more challenging - and I'm not sure how to do it.
I would write it this way, preventing the action from doing anything on the last li as well.
http://jsfiddle.net/h6D4k/6/
$('.next').click(function(e){
e.preventDefault();
if ($("ul.pagination a.active").parent().is(":last-child")) return;
$('ul.pagination a.active').removeClass('active').parent().next().find("a").addClass('active');
});
You have two errors in your code:
Once removed, the active class can't be found anymore
your a tags are nested in li tags so next() doesn't work as you expect
To simplify things, you could attach the active class to the li tags.
Live demo: http://jsfiddle.net/h6D4k/7/
Code:
$('.next').click(function(){
$('ul.pagination').find('li.active').removeClass('active')
.next().addClass('active');
return false;
});
I have a blob of HTML that I'm retrieving using simple jQuery selectors, something like the following:
<div id="stuff">
<ul>
<li>some</li>
<li class="ninja">stuff</li>
</ul>
</div>
I'm basically doing:
var myblock = $("#stuff").html();
now I want to inject an additional li element to the bottom of that li list with very similar attributes to the li above it, but i want to change the class ninja to class samurai.
What's the best way of going about that with jQuery?
Simply select the <ul> and append the <li> to it
$("#stuff ul").append('<li class="samurai">stuff</li>');
If you actually wanted to copy the last <li> element, change the class then add to the list, then you could do something like this
var ul = $("#stuff ul");
ul.append(ul.find('li:last').clone().removeClass().addClass("samurai"));
pass true into clone() if you also want to copy event handlers too.
The problem with taking a whole chunk of HTML, changing an element and then reinserting is that any event handlers set up on elements that will be replaced when you reinsert the HTML will be lost, so it's more elegant/ and less cumbersome/intrusive to simply manipulate the part of the DOM that you need to.