Element is duplicated in a loop - javascript

This code move elements inside other elements to create a tree hierarchy.
<ul>
<li id="task_111" class="task"><a>task1</a></li>
<li id="task_222" data-in-task-group-id="333" class="task"><a>task3</a></li>
<li id="task_333" class="task task_group">
<a>task2</a>
<ul data-task-group-id="333" class="task_group_list"></ul>
</li>
<li id="task_444" data-in-task-group-id="333" class="task task_group">
<a>task4</a>
<ul data-task-group-id="444" class="task_group_list"></ul>
</li>
<li id="task_555" data-in-task-group-id="333" class="task"><a>task5</a></li>
</ul>
Loop that moves the elements:
$('li').each(function() {
task_group_id = $(this).attr('data-in-task-group-id');
if (task_group_id) {
$("li#task_" + task_group_id + " .task_group_list").append($(this));
}
})
All looks pretty simple but one element (task5) is copied wrong:
As you see task5 is placed inside two parent elements: the correct parent is task2, task4 should be empty.
Why is task5 is copied wrong inside task4?
JSfiddle to play around.

What happens is that task4 - including its <ul> element with a class of task_group_list - is moved into task3. Then, when it's the turn of task5 to be moved, there are multiple elements that match this selector:
li#task_333 .task_group_list
As stated in the doc for append:
The .append() method inserts the specified content as the last child of each element in the jQuery collection
Since you have multiple elements you get task5 appended to each of them, cloning the element as necessary.
You'll want to change your selector so that it only matches the <ul> that's an immediate child, rather than a descendent, of that <li> element:
li#task_333 > .task_group_list
The code for the loop would become:
$('li').each(function() {
task_group_id = $(this).attr('data-in-task-group-id');
if (task_group_id) {
$("li#task_" + task_group_id + " > .task_group_list").append($(this));
}
})
Updated jsFiddle

Related

How to toggle list element through DOM Events in Javascript

I have a list containing three elements inside a . I'm trying to toggle on and off a CSS class which strikes the text when the list element is clicked. I've created a function and used a for loop to check for the array index of the list element that was clicked.
I've defined the following:
List Items:
<ul>
<li class="items line-through">Watch</li>
<li class="items line-through">Shoes</li>
<li class="items line-through">Cake</li>
</ul>
var list = document.getElementsByClassName("line-through");
Created a function to toggle the array element from the list based on the index when "click" event happens
function checkItem(index) {
console.log("event = " + index)
list[index].classList.toggle("line-through");
console.log("list = " + index);}
for (var i = 0; i <= list.length; i++) {
console.log("i= " + i);
list[i].addEventListener("click", checkItem(i));}
So after my logic I've declared the for and i index with a value of zero, which is the value of the first list in the array. Then I've added the prints to check if it runs and then checked if list 0, 1, or 2 was clicked. If yes, run function and toggle list[i]. If not, i++ and verify the next one.
The problem is that now it immediately adds the toggle to the first and last items from the list. I've also tried to use querySelectorAll("li") but then it says that list[i] is undefined, which I do not understand why, cause when verifying list[0] in the console it present the first element.
You could refactor your code and use the this keyword to target the clicked element, like this:
document.addEventListener('DOMContentLoaded', () => {
// Execute the code after the HTML content is loaded
const myList = document.querySelector('.my-list');
const listElements = Array.from(myList.children);
listElements.forEach( li => {
li.addEventListener('click', checkItem);
});
function checkItem() {
// The `this` keyword is the clicked element
this.classList.toggle('line-through');
}
});
<ul class="my-list">
<li class="items line-through">Watch</li>
<li class="items line-through">Shoes</li>
<li class="items line-through">Cake</li>
</ul>
This will add the event listener to all the children elements of the list and toggle the line-through class on the clicked one.
Keep in mind that when manipulating the DOM, you should wrap your JS code inside a DOMContentLoaded event listener to prevent selecting elements that are not yet present on the page.

How to find the class of element in a each loop

I am trying to create a menu system where I can change the style of the active page item in the menu. I am using a separate body class on each page, then I want to cycle through the li in the menu and find a match to the body class. At that match I will add the new styling to that menu item.
Here is my code so far.
HTML
<body class="home-state">
...
<div class="menu-left">
<ul>
<li class="home-state">
Home
</li>
<li class="work-state">
Work
</li>
<li class="services-state">
Services
</li>
<li class="about-state">
About
</li>
<li class="blog-state">
Blog
</li>
<li class="shop-state">
Shop
</li>
<li class="contact-state">
<a data-toggle="modal" href="#modal-coworking">Contact</a>
</li>
<li class="project-state">
Project brief
</li>
</ul>
</div>
...
</body>
JS
var bodyClass = $("body").attr('class');
$('.menu-left ul li').each(function(){
First: I want to find the element's class here I have used $(this).attr("class"); which didn't work
var element = $(this);
Second: I want to use a if statement to check to see if the class matches the bodyClass
console.log(element);
Last: If there is a match I want to add the class .active to the element li.
});
Given that elements can have multiple classes, I'd suggesting changing your body element to use a data- attribute rather than a class to specify what the current page is:
<body data-current="home-state">
Then the JS needed to add the active class to the relevant menu item is simple:
$("li." + $("body").attr("data-current")).addClass("active")
You don't need to loop over the menu items comparing classes as mentioned in the question, because you can just directly select the required li element based on its class.
In the event that the body element doesn't have a data-current attribute then $("body").attr("data-current") would return undefined, which would mean the code above tries to select an element with $("li.undefined") and add a class to it. Probably you have no elements with such a class so that would be harmless, but if you wanted to explicitly test that the data-current attribute exists:
var current = $("body").attr("data-current")
if (current) {
$("li." + current).addClass("active")
}
You can do this in couple ways, here is the simple way to do this;
var bodyClass = $("body").attr('class');
$("li." + bodyClass).addClass("active")
You can also use a loop for this one;
var bodyClass = $("body").attr('class');
$(".menu-left li").each(function(i, classes) {
if (bodyClass === $(this).attr("class")) {
$(this).addClass("active")
}
})
both will do the job.
enter image description here
enter image description here
as the comment said,the element can have more than one class ,so you should check it one by one
You missed to bind the click event for the menu item. Follow like below
var bodyClass = $("body").attr('class');
$('.menu-left ul li').on( "click", function() {
var myClass = $(this).attr("class");
alert(myClass);
});
Tested: https://codepen.io/anon/pen/XzYjGY

Put Duplicates under Common Element JavaScript/Jquery

I have the following code.Now I am building the list using Jquery. How do I do this using Javascript/JQuery?
Html(raw)after completion should look like this
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<div>
<ul id="listOne">
<li class="columnItem">John</li><!--will be removed and put under CommonLister-->
<li class="columnItem">James</li>
<li class="columnItem">Mary</li><!--will be removed and put under CommonLister-->
</ul>
<ul id="listTwo">
<li class="columnItem">John</li><!--will be removed and put under CommonLister-->
<li class="columnItem">Mark</li>
<li class="columnItem">Mary</li><!--will be removed and put under CommonLister-->
</ul>
<ul id="CommonLister">
<li class="columnItem">John</li>
<li class="columnItem">Mark</li>
</ul>
</div>
Jquery/JavaScrpit
function myFunctioner(){
$(() => {
let names = [];
let nameSet = new Set();
$("li.columnItemer").each((idx, ele) => {
nameSet.add($(ele).html())
});
var $common = $("<ul>").addClass("commmonLister");
nameSet.forEach((name) => {
if ($("li:contains(" + name + ")").length > 1) {
$("li:contains(" + name + ")").remove();
$("<li>").addClass("columnItemer").html(name).appendTo($common);
}
});
$common.appendTo($(".CommonLister"));
});
}
The above code only works if the list already exists on HTML not when dynamically creating the list. I will be building the list by Ajax query. really appreciate in if you guys can show me how to implement the above code dynamically as the list is built on click event.
Here is what I've got. I don't use the new Javascript notation (not really a fan of it), though I'm sure you could transcribe what I've written into ES if you want to keep it consistent in your project.
I took a very similar approach to you, however I did not dynamically create the element. If you know this element will exist on the page anyway, my personal philosophy is just let it exist there and be empty so that you don't have to create it on your own.
If these lists are being loaded dynamically (something I couldn't really test out while using codepen) then put this into a function called after the list elements have been created. Preferably you would simply go through the data when it is loaded and make the applicable DOM changes only once, but sometimes we do what we must
$(function() {
$('#run-code').on('click', function(e) {
e.preventDefault();
//What were you doing? nope.
var currentItems = {}; //Blank object
var $mergeColumn = $('#CommonLister'); //Common list reference
$('.columnItem').each(function(i, el) {
var $el = $(el); //Notation I use to differentiate between the regular HTML Element and jQuery element
if (!currentItems.hasOwnProperty($el.html())) {
//Has this name come up before? if not, create it.
currentItems[$el.html()] = []; //Make it equal to a brand spanking new array
}
currentItems[$el.html()].push(el);
//Add the item to the array
});
$.each(currentItems, function(name, data) {
//Loop through each name. We don't actually use the name variable because we don't care what someone's name is
if (data.length > 1) {
//Do we have more than 1 element in our array? time to move some stuff
$.each(data, function(i, el) {
var $el = $(el); //See note above
if (i == 0) {
//If this is the first element, let's just go ahead and move it to the merge column ul
$el.appendTo($mergeColumn);
} else {
$el.remove(); //Otherwise, we've already got this element so delete this one.
} //end if/else
}); //end $.each(data)
} //end if data.length >1
}); //end $.each(currentItems)
}); //end $.on()
}); //end $()
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<button id="run-code" class="btn btn-success">Click Me</button>
<h4>List 1</h4>
<ul id="listOne">
<li class="columnItem">John</li>
<!--will be removed and put under CommonLister-->
<li class="columnItem">James</li>
<li class="columnItem">Mary</li>
<!--will be removed and put under CommonLister-->
</ul>
<h4>List 2</h4>
<ul id="listTwo">
<li class="columnItem">John</li>
<!--will be removed and put under CommonLister-->
<li class="columnItem">Mark</li>
<li class="columnItem">Mary</li>
<!--will be removed and put under CommonLister-->
</ul>
<h4>Common List</h4>
<ul id="CommonLister">
</ul>

How to get the current ul li's length in javascript , when i tried to sort them?

<ul id="types" style="list-type:none;">
<li id="categories" style="list-type:none;">1
<ul>
<li style="list-type:none;">1</li><br/>
<li style="list-type:none;">1</li>
</ul>
</li>
<li id="categories" style="list-type:none;">2
<ul>
<li style="list-type:none;">2</li><br/>
<li style="list-type:none;">2</li>
</ul>
</li>
<li id="categories" style="list-type:none;">3
<ul>
<li style="list-type:none;">3</li><br/>
<li style="list-type:none;">3</li>
</ul>
</li>
</ul>
i am moving the li up and down ,when i am doing like this i have written the code for calling one jquery _mouseStop function(event,noPropagation))
in this function i am writing
var tagetNode = this.currentItem[0].parentNode.id
if (this.element[0].id == "categories") {
var targetlistlength = document.getElementById(targetListId).getElementsByTagName("li").length;
// var targetlistlength = this.parentNode.getElementsByTagName("li").length;
var PageIds = "";
for (var i = 0; i < targetlistlength; i++) {
PageIds += document.getElementById(targetListId).getElementsByTagName("li")[i].getAttribute("value") + ",";
}
}
when i am sorting the child li's the above function get called but it is always getting the first child ul of first li length only.. i want the current ul li's length which i am trying to sort
i have tried with the commented line also to get the length of li's but iam getting error as this.parentNode is undefined
anyone please suggest me what can i do
As there is no working demo available, you can check what you get when you use console.log($(this)); inside that function when mouseStop event occurs in console. If you get the expected li in the console then you can executing the following code to get the length of its parent's childs.
alert($(this).parent().children().length);
There mustn't be multiple elements with the same id.
Try to replace them with classes or make them unique.
The if-condition could be the following if you have unique id's (e.g. categories-1, categories-2, ...)
if (this.element[0].id.match("^categories") != null) { ... }
Or if you use classes the if-condition could be:
if (this.element[0].className.match("(^| )categories( |$)") != null) { ... }

reorder list elements - jQuery? [duplicate]

This question already has answers here:
How may I sort a list alphabetically using jQuery?
(10 answers)
Closed 5 years ago.
Is it possible to reorder <li> elements with JavaScript or pure jQuery. So if I have a silly list like the following:
<ul>
<li>Foo</li>
<li>Bar</li>
<li>Cheese</li>
</ul>
How would I move the list elements around? Like put the list element with Cheese before the list element with Foo or move Foo to after Bar.
Is it possible? If so, how?
var ul = $("ul");
var li = ul.children("li");
li.detach().sort();
ul.append(li);
This is a simple example where <li> nodes are sorted by in some default order. I'm calling detach to avoid removing any data/events associated with the li nodes.
You can pass a function to sort, and use a custom comparator to do the sorting as well.
li.detach().sort(function(a, b) {
// use whatever comparison you want between DOM nodes a and b
});
If someone is looking to reorder elements by moving them up/down some list one step at a time...
//element to move
var $el = $(selector);
//move element down one step
if ($el.not(':last-child'))
$el.next().after($el);
//move element up one step
if ($el.not(':first-child'))
$el.prev().before($el);
//move element to top
$el.parent().prepend($el);
//move element to end
$el.parent().append($el);
One of my favorite things about jQuery is how easy it is to write tiny little add-ons so quickly.
Here, we've created a small add-on which takes an array of selectors, and uses it to order the children of the target elements.
// Create the add-on
$.fn.orderChildren = function(order) {
this.each(function() {
var el = $(this);
for(var i = order.length - 1; i >= 0; i--) {
el.prepend(el.children(order[i]));
}
});
return this;
};
// Call the add-on
$(".user").orderChildren([
".phone",
".email",
".website",
".name",
".address"
]);
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul class="user">
<li class="name">Sandy</li>
<li class="phone">(234) 567-7890</li>
<li class="address">123 Hello World Street</li>
<li class="email">someone#email.com</li>
<li class="website">https://google.com</li>
</ul>
<ul class="user">
<li class="name">Jon</li>
<li class="phone">(574) 555-8777</li>
<li class="address">123 Foobar Street</li>
<li class="email">jon#email.com</li>
<li class="website">https://apple.com</li>
</ul>
<ul class="user">
<li class="name">Sarah</li>
<li class="phone">(432) 555-5477</li>
<li class="address">123 Javascript Street</li>
<li class="email">sarah#email.com</li>
<li class="website">https://microsoft.com</li>
</ul>
The function loops backwards through the array and uses .prepend so that any unselected elements are pushed to the end.
Here is a jQuery plugin to aid with this functionality: http://tinysort.sjeiti.com/
something like this?
​var li = $('ul li').map(function(){
return this;
})​.get();
$('ul').html(li.sort());
demo
I was somewhat lost you may be wanting something like this...
$('ul#list li:first').appendTo('ul#list'); // make the first to be last...
$('ul#list li:first').after('ul#list li:eq(1)'); // make first as 2nd...
$('ul#list li:contains(Foo)').appendTo('ul#list'); // make the li that has Foo to be last...
more of it here1 and here2
Have a look at jquery ui sortable
http://jqueryui.com/demos/sortable/

Categories

Resources