Appending elements through JavaScript for dynamically generated id - javascript

<li class="list" id='+id+'>
<a class="anchor" id='+id+' href='#stay' onClick="getValue(this);" style="text-decoration: none, color:red">hello</a>
Now inside JavaScript:
listElem=listElem+'<li class="list" style="height: 18px; display: inline- block;width:100px;line-height: 20px;padding-right:25px;"><a class="anchor" id=""+results+"" href="#stay" style="width:1028px;">"+results+"</a> </li>';
Now I need to append the listElem after li tag. Since id is dynamically generated.
How could I append it through innerHTML or html()?
How could I pass id here: $( "" ).html(listElem); or is here any other method?

You're probably looking for jQuery's insertAfter() and prop() methods.
If, say you have your HTML code in a a variable listItem, you can convert it to jQuery object, use prop() to set id and then insertAfter() to place it the last <li> element with a class="list":
var listElem = jQuery('<li class="list" style="height: 18px; display: inline-block;width:100px;line-height: 20px;padding-right:25px;"><a class="anchor" id=""+results+"" href="#stay" style="width:1028px;">"+results+"</a></li>');
listElem.prop('id', id).insertAfter('li.list:last');

If I understand your question correctly, then jQuery provides the before method of jQuery objects. To append listElem before the li element, you could call
$('#+id+').before(listElem);

you can do like this on click event
<li class="list" id='+id+' onclick='getvalue(this)'>
<a class="anchor" id='+id+' href='#stay' onClick="getValue(this);" style="text-decoration: none, color:red">hello</a>
jQuery code:
function getvalue(elem){
var listElem='<li class="list" style="height: 18px; display: inline- block;width:100px;line-height: 20px;padding-right:25px;"><a class="anchor" id=""+results+"" href="#stay" style="width:1028px;">"+results+"</a> </li>';
var id=$(elem).attr('id');
$('#'+id).html(listElem);//your code
}

Here is an option:
var ul = document.querySelector('ul');
var li1 = makeLi();
var li2 = makeLi();
var li3 = makeLi();
insert(ul, li2); // insert #my-uid-2
insert(ul, li1); // insert #my-uid-1
insert(ul, li3); // insert #my-uid-3
function uid () {
var i = 1;
return (this.uid = function () {
return 'my-uid-' + (i++);
})();
};
function makeLi () {
var re = /\+id\+/g;
var ul = document.createElement('ul');
var li = '<li id="+id+">#+id+</li>';
return (this.makeLi = function () {
ul.innerHTML = li.replace(re, uid());
return ul.firstChild;
})();
}
function insert (ul, li) {
var child;
var i = 0;
var re = /^.*?(\d+)$/;
var n = +li.id.replace(re, '$1');
var children = ul.childNodes;
while (
(child = children[i]) &&
n > +child.id.replace(re, '$1')
) i++;
if (child) ul.insertBefore(li, child)
else ul.appendChild(li);
}
#my-uid-1 {
background: yellow;
}
#my-uid-2 {
background: orange;
}
#my-uid-3 {
background: red;
}
<ul></ul>

Related

How to remove <li> list items and make the remaining ones change their position and id?

Tricky question and far too advanced for my level (js student).
Lets say I use the append method to generate <li> items inside an <ol>, and I need each one of those li items to have a unique id, so I thought to get the amount of <li> (length) items I generated by saying this : var index = document.getElementById("ol1").getElementsByTagName("li").length+1; and use this number to create unique id's for every item I generate by doing this: li.id="li"+index; so the first one I generate becomes #li1 (since the amount of li items is one), the next one #li2 and so on. *btw, is it the right approach to do this?
Now lets say I want to remove #li1, then #li2 would replace it in position 1 of the list, but its id will still be #li2 since it has gotten it already.
For example what I ultimately want is when I remove #li1, then #li2 becomes #li1, #li3 becomes #li2, #li4 becomes #li3.....and so on.
What would be the right logic approach to do such a gimmick?
function append() {
var index = document.getElementById("ol1").getElementsByTagName("li").length + 1;
var ol = document.getElementById("ol1");
var li = document.createElement("li");
li.id = "li" + index;
li.innerHTML = (`LIST ITEM <input value=this is id: #li${index}><button class=remove id= button${index} onclick=remove${index}()>REMOVE</button>`);
ol.append(li)
}
function remove1() {
var rem = document.getElementById("li1");
rem.remove();
}
function displayIndex() {
var index = document.getElementById("ol1").getElementsByTagName("li").length;
alert(index);
}
#li1 {
color: red;
}
#li2 {
color: green;
}
#li3 {
color: blue;
}
ol button {
color: red;
visibility: hidden;
}
#button1 {
color: red;
visibility: visible;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head>
<button id="btn1" onclick="append()">Append</button>
<button id="btn2" onclick="displayIndex()">Index</button>
</head>
<body>
<ol id="ol1">
</ol>
</body>
</html>
First off:
There are no "right" approaches. Only working implementations. How it is achieved might differ from developer to developer, and as long as it works, it should be considered the "right" way (however, not necessarily the most efficient or optimized or any other way).
One way would be to use a remove() function that re-assigns the ID's of the remaining <li>s (after the removal, obviously) as a side-effect.
function removeItemOf(list, listItem) {
if (!list.contains(listItem)) return;
listItem.remove();
indexItemsOf(list);
// For displaying the removed ID on-screen
document.querySelector('div').append(
document.createElement('br'),
document.createTextNode(`Removed <li> with id '${listItem.id}'`)
);
}
function indexItemsOf(list) {
for (var i = 0; list.children[i]; ++i) {
list.children[i].id = (list.id || list.tagName) + '-li' + i;
// For displaying the <li>'s ID on-screen
list.children[i].textContent = `With ID '${list.children[i].id}'`;
}
}
var list = document.querySelector('ol');
indexItemsOf(list);
setTimeout(() => {
removeItemOf(list, list.children[0]);
}, 2000);
setTimeout(() => {
removeItemOf(list, list.children[1]);
}, 4000);
<ol>
<li></li>
<li></li>
<li></li>
<li></li>
</ol>
<div></div>
However, re-assigning a previously used ID makes it not unique to one element, as it now identifies another element it hasn't identified before. For environments where this would be important (e.g. relying on an element to reference certain other elements, or to have a certain event-listener, etc.), re-using an ID would break the environment.
To circumvent this problem, one could keep track of how many unique items a list had over its entire lifetime, and create the next item with an ID using that amount, and then increase the amount by one.
Here is an example:
var list = document.querySelector('ol');
list.uniqueItems = 0;
// Here: Using Event-Delegation for removing a <li>
list.addEventListener('click', function(evt) {
if (evt.target.classList.contains('btn-delete'))
evt.target.closest('li').remove();
});
document.querySelector('button').addEventListener('click', function() {
var item = document.createElement('li');
item.id = 'li-' + list.uniqueItems;
item.textContent = `Has the ID '${item.id}' `;
var btnDelete = document.createElement('button');
btnDelete.classList.add('btn-delete');
btnDelete.textContent = 'Delete Item';
item.append(btnDelete);
list.append(item);
list.uniqueItems++;
});
<button>New Item</button>
<ol></ol>
You can just loop through each list item after your remove one and regenerate the IDs for each.
ol = document.getElementById("ol1");
function indexLIs(){
i = 1;
ol.querySelectorAll("li").forEach(function(li){
id = "li" + i;
li.setAttribute("id",id);
li.querySelector("input").value = "this is id: #" + id;
i++;
});
}
function append() {
var index = document.getElementById("ol1").getElementsByTagName("li").length + 1;
var li = document.createElement("li");
li.id = "li" + index;
li.innerHTML = (`LIST ITEM <input value=this is id: #li${index}><button class=remove id= button${index} onclick=remove${index}()>REMOVE</button>`);
ol.append(li)
}
function remove1() {
var rem = document.getElementById("li1");
rem.remove();
indexLIs();
}
function displayIndex() {
var index = document.getElementById("ol1").getElementsByTagName("li").length;
alert(index);
}
#ol1 li:nth-child(1) {
color: red;
}
#ol1 li:nth-child(2) {
color: green;
}
#ol1 li:nth-child(3) {
color: blue;
}
ol button {
color: red;
visibility: hidden;
}
#button1 {
color: red;
visibility: visible;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<html>
<head>
<button id="btn1" onclick="append()">Append</button>
<button id="btn2" onclick="displayIndex()">Index</button>
</head>
<body>
<ol id="ol1">
</ol>
</body>
</html>
Your approach is fine. It would be easier for you to keep counting from the last element without changing the other elements even if you remove an element. In that situation use a global variable and initialize it with the length of your initial list. Something like that should do the work:
var index = 1; // or the index you wish to start from
function append(){
var ol = document.getElementById("ol1");
var li = document.createElement("li");
li.id="li"+index;
li.innerHTML = (`LIST ITEM <input value=this is id: #li${index}><button class=remove id= button${index} onclick=remove${index}()>REMOVE</button>`);
ol.append(li);
// now we will increment our index for the next iteration
index++;
}
Hope this was useful.

How to use closest() in a proper way in js

Student here!
Lets say i have function append() which generates <li> items inside an <ol>,those li items contain 2 buttons,one for removing the <li> that lies within and one for creating the same item but inside itself this time,in order to make another list layer.
Both by using the closest() method.
i cant figure out how to use the ADD <button>,i can call it but i cannot it make it work the way i want to.
I get this :
But i want to get something like this :
this is how i'm trying to do it :
function append() {
var ol = document.getElementById("ol1");
var li = document.createElement("li");
li.innerHTML = (`LIST ITEM <input class=input><button class=add>ADD</button><button class=remove>REMOVE</button>`);
ol.append(li)
document.getElementById("ol1").addEventListener("click",function(e) {
const tgt = e.target;
if (tgt.classList.contains("remove")) tgt.closest("li").remove();
if (tgt.classList.contains("add")) tgt.closest("li").appendChild(li);
})
}
<html>
<body>
<button id="btn1" onclick="append()">Append</button>
<ol id="ol1">
</ol>
</body>
</html>
To number with 1., 1.1, 1.2, 2., 2.1, 3., you need to use CSS. The counters function, obtains the number of the li. Each time an ol appears, the counter is reset to 1.. When a li appears, the top counter is used, concatenated with the new next new number of the previous li.
ol {
counter-reset: item
}
li {
display: block;
}
li:before {
content: counters(item, ".") ". ";
counter-increment: item;
}
In the append function, we add the li... For this, we call another function, which we will call create_li() which does the creation of the li.
function append() {
document.querySelector("#ol1").append( create_li() )
}
In the create_li() function, we create the li and return it with return li. In li, we add the two button elements, add and remove, but instead of doing it through a string, we do it with the function we already know, that is to say, document.createElement(), and also, on each button, we can add una función que llamaremos button_click function, used to receive the click event through addEventListener.
function create_li(){
var li = document.createElement("li")
var add = document.createElement("button")
var remove = document.createElement("button")
li.innerHTML = "LIST ITEM <input class=input>"
add.className = "add"
remove.className = "remove"
add.innerHTML = "+"
remove.innerHTML = "-"
add.addEventListener("click",button_click)
remove.addEventListener("click",button_click)
li.appendChild(add)
li.appendChild(remove)
return li
}
The button_click function, what it does is create the ol and li structure. In addition, it detects if the button clicked is the add or remove.
function button_click(e) {
const tgt = e.target;
var litg = tgt.closest("li")
var oltg = litg.querySelector("ol")
if(oltg==null){
var ol = document.createElement("ol")
litg.appendChild(ol)
oltg = ol
}
if (tgt.classList.contains("remove")){
litg.remove()
}
if (tgt.classList.contains("add")){
oltg.appendChild( create_li() )
}
}
The HTML structure is based on the li has to be inside the ol, and each sublist has to have an ol inside the li.
<ol>
<li>
1.
<ol>
<li>1.1</li>
<li>1.2</li>
<li>1.3</li>
</ol>
</li>
<li>
2.
<ol>
<li>2.1</li>
<li>2.2</li>
<li>2.3</li>
</ol>
</li>
<li>
3.
<ol>
<li>3.1</li>
<li>3.2</li>
<li>3.3</li>
</ol>
</li>
</ol>
Finished code:
function button_click(e) {
const tgt = e.target;
var litg = tgt.closest("li")
var oltg = litg.querySelector("ol")
if(oltg==null){
var ol = document.createElement("ol")
litg.appendChild(ol)
oltg = ol
}
if (tgt.classList.contains("remove")){
litg.remove()
}
if (tgt.classList.contains("add")){
oltg.appendChild( create_li() )
}
}
function create_li(){
var li = document.createElement("li")
var add = document.createElement("button")
var remove = document.createElement("button")
li.innerHTML = "LIST ITEM <input class=input>"
add.className = "add"
remove.className = "remove"
add.innerHTML = "+"
remove.innerHTML = "-"
add.addEventListener("click",button_click)
remove.addEventListener("click",button_click)
li.appendChild(add)
li.appendChild(remove)
return li
}
function append() {
document.querySelector("#ol1").append( create_li() )
}
ol {
counter-reset: item
}
li {
display: block;
}
li:before {
content: counters(item, ".") ". ";
counter-increment: item;
}
<button id="btn1" onclick="append()">Append</button>
<ol id="ol1"></ol>
This is probably what you want?
function append() {
var ol = document.getElementById("ol1");
var li = document.createElement("li");
li.innerHTML = (`LIST ITEM <input class="input"><button class="add" onclick="add(this)">ADD</button><button class="remove" onclick="remove(this)">REMOVE</button><ol></ol>`);
ol.append(li)
}
function add(e) {
var li = document.createElement("li");
li.innerHTML = (`LIST ITEM <input class="input"><button class="add" onclick="add(this)">ADD</button><button class="remove" onclick="remove(this)">REMOVE</button><ol></ol>`);
e.parentElement.getElementsByTagName("ol")[0].appendChild(li);
}
function remove(e) {
e.parentElement.parentElement.removeChild(e.parentElement);
}
<html>
<body>
<button id="btn1" onclick="append()">Append</button>
<ol id="ol1">
</ol>
</body>
</html>
Instead of using 'closest' in the add method, you can simply find the parent and append in that.
EG : tgt.parentNode().appendchild(childLi)

JavaScript: query children and modify parent

I have a static generated unsorted list and need to modify the parent li for a given child-href-match. This action should perform by rendering, not by interaction. I am using jQuery 1.12.4.
<div id="archive_widget" class="widget-odd widget-last widget-first widget-1 widget Archive_Widget">
<h3>Archive</h3>
<ul>
<li>2018</li>
<li>2017</li>
<li>2016</li>
<li>2015</li>
<li>2014</li>
<li>2013</li>
<li>2012</li>
<li>2010</li>
<li>2009</li>
</ul>
</div>
I don't know how to do this with JS, but this imaginary JS was in my mind.
jQuery(document).ready(function() {
var current = "<?php echo $current; ?>";
var ArchiveList = document.querySelector('#archive_widget ul li').children;
for (i = 0; i < productList.length; i++) {
if (productList[i].text == current) {
$(productList[i]).parent().addClass('active-menu');
}
}
});
Thank you.
There are some problems with your code:
document.querySelector select only one element, in your case the first LI
variable productList is never declared
The parent of a LI is always a list, not the LI itself.
Here is a working version of it:
$(document).ready(function() {
var current = "2014";
var productList = $('#archive_widget ul li a'); // select all A elements
for (i = 0; i < productList.length; i++) {
if ($(productList[i]).text() === current) {
$(productList[i]).parent().addClass('active-menu'); // Parent of A will be LI
}
}
});
Ideally, this would be set when SSR, but here's a scant attempt:
$(document).ready(function () {
let current = "2015";//set server-side
let found = false;
$("#archive_widget").children('ul').children("li").children("a").each(function () {
if (!found && $(this).text() === current) {
$(this).parent().addClass('active-menu');
found = true;
}
});
});
.active-menu { background: red }
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div id="archive_widget" class="widget-odd widget-last widget-first widget-1 widget Archive_Widget">
<h3>Archive</h3>
<ul>
<li>2018</li>
<li>2017</li>
<li>2016</li>
<li>2015</li>
<li>2014</li>
<li>2013</li>
<li>2012</li>
<li>2010</li>
<li>2009</li>
</ul>
</div>
I hope this helps!
Change ArchiveList to productList since that's what your code is using and use .textContent instead of .text.
Your query selector only matches one element. You want to match all of the anchor elements whose parents are a li, so use document.querySelectorAll instead:
document.querySelectorAll('#archive_widget ul li a');
Fixed Code:
jQuery(document).ready(function() {
var current = "<?php echo $current; ?>";
var productList = document.querySelectorAll('#archive_widget ul li a');
for (i = 0; i < productList.length; i++) {
if (productList[i].textContent == current) {
$(productList[i]).parent().addClass('active-menu');
}
}
});

include variable with addEventListener

I´ve just started to learn JavaScript and made a click function to change value of i depending on which li element is being clicked. Instead of having 3x of basically same function is it possible to send variable with addEventLisener to check with a if statement. Because if I add 1 or 2 more li it would add a lot of unnecessary code.
HTML:
<div><img src="image1" />
<ul>
<li id="list1">1</li>
<li id="list2">2</li>
<li id="list3">3</li>
</ul>
</div>
JavaScript:
var list1 = getElementById('list1');
var list2 = getElementById('list2');
var list3 = getElementById('list3');
list1.addEventListener("click", clicked1);
list2.addEventListener("click", clicked2);
list3.addEventListener("click", clicked3);
var i = 0;
function clicked1(){
i= 0;
loop();
}
function clicked2(){
i = 1;
loop();
}
function clicked3(){
i = 2;
loop();
}
function loop(){
if (i > 2){
i=0;
}
var imageloop = getElementById('slideshow').getElementsByTagName('img');
imageloop[0].src = 'image' + i;
i++
setTimeout(loop,3000);
}
So when one of the li element is being clicked it will change the img currently displaying.
Bind to the list, not the list item - <ul id="ul1">... :
document.getElementById('ul1').addEventListener('click', function (e) {
var li = e.target;
alert(li.id); // list1, list2, respectively, etc.
});
http://jsfiddle.net/seancannon/D6HX4/
As Teemu said, bind to the list and use e.target. Then, change i according to e.target.innerHTML (because for your purposes, that's easier since the innerHTML is similar to the id, but simpler).
Assuming the <ul> element now has an id of "list":
var list = document.getElementById("list");
var i = null;
list.addEventListener("click", function(e) {
window.i = parseInt(e.target.innerHTML, 10);
console.log(window.i);
});
You don't need Separate code for each <li>,
Here is How to do it in single function:
HTML:
<div>
<ul id="All_List">
<li id="list1">1</li>
<li id="list2">2</li>
<li id="list3">3</li>
</ul>
</div>
JavaScript:
var clicked_li=0; /* It'll store the number of <li> being clicked */
var ul=document.getElementById("All_List"); /* <ul> Element with all <li> */
window.onload=function(){
var lis=ul.getElementsByTagName("li"); /* All <li>'s from <ul> */
for(var i=0;i<lis.length;i++){
var li=lis[i]; /* Specific <li> from <ul> ie, lis[0] means first <li> of <ul> */
li.addEventListener("click", function(){ /* Listen and bind click event to that <li> */
clicked_li=getIndex(this); /* Store Which <li> Was clicked in clicked_li */
alert("'list"+clicked_li+"' was clicked!");
/* if you just want to get the id you can use event.target.id; instead of getIndex(); */
}, false);
}
};
function getIndex(node) {
var childs = node.parentNode.getElementsByTagName("li"); /* Get parent <ul> and all child <li> of that parent */
for (var i = 0; i < childs.length; i++) {
if (node == childs[i]) break; /* Find which <li> from current <ul> was clicked */
}
return (i+1); /* Return No.(index) of that <li> starting with 1 */
}
and here is the:
fiddle for the same.
Hope it'll help you. Cheers!
This is an "improve/clearer" of Vedant Terkar answer. Which may give a more clear aspect on
the answer he gave.
if we give ul id group. We dont need id for each of the list-item inside the ul.
<ul id="group">
<li>1</li>
<li>2</li>
<li>3</li>
</ul>
Javascript
var i=0;
we set i to be a global variable and equal to 0 assuming it will display image(0) if nothing else is called.
window.onload=function(){
var lis=document.getElementById("group").getElementsByTagName('li');
We are now creating a Nodelist which is called lis. Then we loop through the NodeList to se which list-element is being clicked at.
for(i=0;i<lis.length;i++){
var li=lis[i];
li.addEventListener("click",index, false);
}
}
function index(){
var lis = document.getElementById("group").getElementsByTagName('li');
i = getIndex(this);
for(var a=0; a < lis.length; a++){
if(a ==i){
lis[i].innerHTML = 'Choosen';
}else{
lis[a].innerHTML = 'list'+a;
}
}
}
function getIndex(node) {
var childs = node.parentNode.getElementsByTagName("li");
for (var i = 0; i < childs.length; i++) {
if (node == childs[i]) break;
}
return (i);
}

How check in javascript that a li element has inner ul?

Good day.
HTML:
<ul>
<li class="sub">catalog
<ul>
<li class="dir">subcatalog
<ul>
<li>sublink</li>
<li>sublink</li>
<li>sublink</li>
</ul>
</li>
<li class="dir">subcatalog</li>
<li class="dir">subcatalog</li>
</ul>
</li>
<li class="sub">catalog</li>
<li class="sub">catalog</li>
<li class="sub">catalog</li>
<li class="sub">catalog</li>
</ul>
<style>
ul > li.sub:hover > ul{display:block;}
ul > li.sub:hover{
background: #fff url(../../images/arrow1.png) no-repeat 91% center;
border-bottom: 2px solid #e30613;
padding-right: 25px;
}
</style>
I use script:
$('li.main_menu_top_li').has('ul').addClass('sub');
Tell me please how make it on javascript (only javascript)?
One of two ways.
first get the element:
var d = document.getElementByClassName("li.main_menu_top_li");
Then:
if (d.firstChild) {
// It has at least one
d.className = d.className + " sub";
}
or the hasChildNodes() function:
if (element.hasChildNodes()) {
// It has at least one
d.className = d.className + " sub";
}
Assuming you want to add the sub class to the LI that has nested ULs under it:
Plain JS
var li = document.querySelector('li.main_menu_top_li');
if (li.getElementsByTagName("ul").length>0) li.className+="sub";
// or get the addClass/hasClass from http://snipplr.com/view/3561/
jQuery:
var li = $('li.main_menu_top_li');
if (li.children('ul').length) li.addClass('sub');
If you want to add the class to any UL that is inside an LI then
var li = $('li.main_menu_top_li');
li.children('ul').each(function() {
$(this).addClass('sub');
});
The following code looks at all LI elements and checks if they have a UL element. If so, that UL element gets the class 'sub'. If you want instead for that LI to have the class 'sub', un-comment the commented portions of code and then remove the line underneath each commented line.
Here's the first jsfiddle:
//IE 10+ and all other major browsers
var el = document.getElementsByTagName('li');
var listItems = Array.prototype.slice.call(el);
listItems.forEach(function(el) {
var childrenList = Array.prototype.slice.call(el.children);
childrenList.forEach(function(el) {
if(el.tagName === 'UL') {
//if(!el.parentNode.classList.contains('sub') {
if(!el.classList.contains('sub')) {
//el.parentNode.classList.add('sub')
el.classList.add('sub');
}
}
});
});
Here's the second jsfiddle:
//IE8+ and all other major browsers, I think
var el = document.getElementsByTagName('li');
var listItems = Array.prototype.slice.call(el);
listItems.forEach(function(el) {
var childrenList = Array.prototype.slice.call(el.children);
childrenList.forEach(function(el) {
if(el.tagName === 'UL') {
//if(el.parentNode.className === '') {
if(el.className === '') {
//el.parentNode.className = 'sub'
el.className = 'sub';
} else {
//el.parentNode.className += 'sub'
el.className += ' sub';
}
}
});
});

Categories

Resources