Hello how can i loop through ul li elements and get the text content only from the li, excepting the text content of its children?
<li class="lom">#paul<div class="on-off">offline</div></li>
<li class="lom">#alex<div class="on-off">offline</div></li>
<li class="lom">#jhon<div class="on-off">offline</div></li>
I want to get only the #paul without offline,
I have tried this:
var lnx = $('.cht(ul class) .lom');
for (let i = 0; i < lnx.length; i++) {
var txt = lnx[i].textContent;
console.log(txt + '\n');
}
But i get #pauloffline
Iterate through the .childNodes, filtering by nodeType of 3 (text node), to get only nodes that are text node children:
const texts = [...document.querySelector('.lom').childNodes]
.filter(node => node.nodeType === 3)
.map(node => node.textContent)
.join('');
console.log(texts);
<ul>
<li class="lom">#paul<div class="on-off">offline</div></li>
</ul>
Jquery solution using replace
https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Global_Objects/String/replace
$('.lom').each(function(index, value) {
var getContent = $(this).text();
var replaceTxt = getContent.replace('<div class="on-off">offline</div>','').replace('offline','');
//$(this).find('.on-off').remove();
if (replaceTxt == '#paul') {
console.log(replaceTxt);
}
});
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<li class="lom">#paul<div class="on-off">offline</div></li>
<li class="lom">#alex<div class="on-off">offline</div></li>
<li class="lom">#jhon<div class="on-off">offline</div></li>
Here's a jQuery variant that uses the .ignore() micro plugin
$.fn.ignore = function(sel) {
return this.clone().find(sel||">*").remove().end();
};
// Get LI element by text
const $userLI = (text) =>
$(".lom").filter((i, el) => $(el).ignore().text().trim() === text);
// Use like
$userLI("#paul").css({color: "gold"});
<ul>
<li class="lom">#paul <span class="on-off">offline</span></li>
<li class="lom">#alex <span class="on-off">offline</span></li>
<li class="lom">#jhon <span class="on-off">offline</span></li>
<li class="lom">#paul</li>
</ul>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>
Related
I'm working with the Docsify.js markdown parser framework and it automatically creates a sidebar from the headings in a document (unless you manually create a sidebar).
I have some CSS that numbers list elements, but want to convert it to JS as there are rendering issues when classes are added as the page scrolls (ie. adding .active).
Originally, I was trialling using this snippet but it doesn't output it as an auto incrementing hierarchical number system:
The sidebar that is generated is in the following format:
var li = document.getElementsByTagName( 'li' );
for( var i = 0; i < li.length; i++ ) {
var prefix = '1.';
li[i].innerHTML = prefix + ' Title ' + i;
prefix++;
}
<aside class="sidebar">
<div class="sidebar-nav">
<ul>
<li>Title 1</li>
<ul>
<li>Title 2</li>
<ul>
<li>Title 3</li>
<ul>
<li>Title 4</li>
<ul>
<li>Title 5</li>
<ul>
<li>Title 6</li>
</ul>
</ul>
</ul>
</ul>
</ul>
<li>Title 1</li>
<li>Title 1</li>
<ul>
<li>Title 2</li>
<li>Title 2</li>
<ul>
<li>Title 3</li>
<ul>
<li>Title 4</li>
<ul>
<li>Title 5</li>
<ul>
<li>Title 6</li>
</ul>
</ul>
</ul>
</ul>
</ul>
</ul>
</div>
</aside>
I understand the HTML structure isn't valid with <ul> being a descendant of an <ul> but this is the code that is outputted and I have no control over it.
However, I want to be able to number the headings with sections and sub-sections:
1. Title 1
1.1. Title 2
1.1.1. Title 3
1.1.1.1. Title 4
1.1.1.1.1. Title 5
1.1.1.1.1.1. Title 6
2. Title 1
3. Title 1
3.1. Title 2
3.2. Title 2
3.2.1. Title 3
3.2.1.1. Title 4
3.2.1.1.1. Title 5
3.2.1.1.1.1. Title 6
I am struggling to find a way to be able to target the first <li> (or the H1), and then being able to access the next <ul> via .nextElementSibling to continue the loop and prepend the numbering.
As far as I have gotten to at the moment is: document.querySelectorAll( 'div.sidebar-nav > ul' ) and it's not much to go on!
I think I'm really out of my depth for javascript here, and was hoping that I'd be able to get some help on being able to loop through the <li> and <ul> elements to prepend the numbers.
Following is JavaScript to apply nested index numbers. At max there are only 6 header tags, 6 levels, so we can use recursive solution:
let startLevel = 1;
let endLevel = 5;
function indexsify() {
let children = document.querySelectorAll('#sidebar > ul');
let numbers = new Array(7).fill(0);
let depth = 0;
children.forEach((element, index) => {
recurse(element, ++depth, numbers);
});
}
function recurse(element, depth, numbers) { //ul
let children = Array.from(element.children);
children.forEach((element, index) => {
if (element.localName.toUpperCase() === 'LI') {
numbers[depth]++;
addNumberString(element, depth, numbers);
} else if (element.localName.toUpperCase() === 'UL') {
if (depth < endLevel) {
recurse(element, depth + 1, numbers, startLevel);
numbers.fill(0, depth + 1); //reset all next numbers
}
}
});
}
function addNumberString(element, depth, numbers) {
let strNumber = "";
numbers.forEach((num, index) => {
if (index > depth || index <= startLevel) return;
strNumber += `${num}.`;
});
element.firstElementChild.innerText = strNumber +
element.firstElementChild.innerText;
}
indexsify();
ul,
li {
list-style-type: none;
}
<div id="sidebar">
<ul>
<li><a>Home</a></li>
<ul>
<li><a>Chapter a</a></li>
<ul>
<li><a> Section a</a></li>
<li><a>Section b</a></li>
</ul>
<li><a>Chapter b</a></li>
<li><a>Chapter c</a></li>
<ul>
<li><a>Section a</a></li>
<li><a>Section b</a></li>
<ul>
<li><a>Sub-section a</a></li>
</ul>
</ul>
<li><a>Chapter D</a></li>
</ul>
</ul>
</div>
Modify markdown itself: As per the Docsify plugin documentation there is no direct provision to influence the sidebar content. Your plugin uses hook.afterEach(function(html, next) and the sidebar is generated separately. So you are trying to manipulate generated sidebar also. You are trying to do similar operation two times.
Why not use hook.beforeEach(function(content) and manipulate markdown itself. That way you'll have to do the numbering operations only once.
Here is a demo site and the code sandbox link for following sample plugin that manipulates markdown content:
<!DOCTYPE html>
<html>
<body>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/docsify#4/themes/vue.css"
/>
<link
rel="stylesheet"
href="https://cdn.jsdelivr.net/npm/docsify/themes/dark.css"
/>
<div id="app">Please wait...</div>
<script>
window.$docsify = {
el: "#app",
loadSidebar: true,
maxLevel: 4,
subMaxLevel: 5,
homepage: "readme.md"
};
</script>
<script>
//plugin
let myPlugin = function (hook, vm) {
hook.init(function () {
//remove '-' before Table of content entries
let customStyles = document.createElement("style");
customStyles.type = "text/css";
customStyles.textContent = `.app-sub-sidebar li::before {
content: '' !important;
padding-right: 4px;
float: left;
}`;
document.body.appendChild(customStyles);
});
//update markdown content before docsify parsing
hook.beforeEach(function (content) {
let lines = content.split("\n");
let numbers = new Array(6).fill(0);
let depth = 0;
lines.forEach((line, index) => {
let level = getLevel(line);
//if not a header continue to next line
if (level === -1) return;
if (level > depth) {
depth++; //increase depth
} else {
depth = level; //decrease depth
numbers.fill(0, depth + 1); //set all next depth to 0
}
numbers[depth]++;
let strNumber = "";
numbers.forEach((num, index) => {
if (index > depth || index < startLevel) return;
strNumber += `${num}.`;
});
if (depth < endLevel) {
lines[index] =
levels[level] + strNumber + line.substr(depth + 1, line.length);
}
});
//update original content
content = lines.join("\n");
return content;
});
let levels = ["# ", "## ", "### ", "#### ", "##### ", "###### "];
let startLevel = 1;
let endLevel = 4;
let regEx = new RegExp(`^#{1,${endLevel}}\\s+.*`);
function getLevel(line) {
if (!regEx.test(line)) return -1; //not a header line
if (line.startsWith(levels[0])) return 0; //h1
if (line.startsWith(levels[1])) return 1;
if (line.startsWith(levels[2])) return 2;
if (line.startsWith(levels[3])) return 3;
if (line.startsWith(levels[4])) return 4;
if (line.startsWith(levels[5])) return 5; //h6
}
};
window.$docsify.plugins = [myPlugin];
</script>
<script src="https://cdn.jsdelivr.net/npm/docsify#4"></script>
</body>
</html>
We need to override default CSS in hook.init(function ()) to remove leading - in table of contents.
Old answer: You can have numbers directly on anchors<a> tags :
.sidebar ul>li {
counter-increment: item;
}
.sidebar ul>li:first-child {
counter-reset: item;
}
.sidebar ul>li a::before {
content: counters(item, ".") " ";
}
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify#4/themes/vue.css" />
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/docsify/themes/dark.css" />
<div id="app">Please wait...</div>
<script>
window.$docsify = {
el: "#app",
loadSidebar: false,
homepage: 'https://gist.githubusercontent.com/OnkarRuikar/bb1d986f279dddceea9004a4bde3844b/raw/80fe153d6b8c1bb2b8e7035be7df1bb908779061/readme.md'
}
</script>
<script src="https://cdn.jsdelivr.net/npm/docsify#4"></script>
If you generate numbers for titles in main section then they may get populated automatically in the sidebar. You can use markdown setting to write the script. Or you can try something like: https://github.com/markbattistella/docsify-autoHeaders
You want to "do something" to every child of the outer UL, depending on its type - either increment the index at the current level and then prepend a label, if it's an LI; or else recurse to the next level, if it's a UL. Given the HTML provided by the OP, this bit of code produces exactly the desired result:
function addLabels(element, prefix) {
var index = 0;
Array.from(element.children).forEach(element => {
if (element.localName.toUpperCase() === 'LI') {
index += 1;
element.innerText = prefix + index + '. ' + element.innerText;
} else if (element.localName.toUpperCase() === 'UL') {
addLabels(element, prefix + index + '.');
}
});
}
document.querySelectorAll('div.sidebar-nav > ul').forEach(
element => addLabels(element, '')
);
Also, you mentioned the idea of using nextElementSibling to get the UL's from the LI's. That would work, but I think you'd end up with code that is less robust, less performant, and not particularly clearer. But for the record, that could look something like this:
function addLabels2(element, prefix) {
Array.from(element.querySelectorAll(':scope > li')).forEach((element, index) => {
var label = prefix + (index+1) + '.';
var sibling = element.nextElementSibling;
element.innerText = label + ' ' + element.innerText;
if (sibling && sibling.localName.toUpperCase() === 'UL') {
addLabels2(sibling, label);
}
});
}
document.querySelectorAll('div.sidebar-nav > ul').forEach(
element => addLabels2(element, '')
);
I need to concatenate all the title value starting from second li elements with Javascript.
The problem is that I want to use it in different pages, so I can't know the exact number of li elements.
<div id="breadcrumb">
<ul>
<li title="One">One</li>
<li title="Two">Two</li>
<li title="Three">Three</li>
<li title="Four">Four</li>
</ul>
</div>
I use a variable for each element but if one or more element is missing the var is not valid and the concat function doesn't work.
var a = document.querySelector(".breadcrumb li:nth-child(2) > a").getAttribute("title");
var b = document.querySelector(".breadcrumb li:nth-child(3) > a").getAttribute("title");
var c = document.querySelector(".breadcrumb li:nth-child(4) > a").getAttribute("title");
var d = document.querySelector(".breadcrumb li:nth-child(4) > a").getAttribute("title");
var str = a.concat(b,c,d);
console.log(str)
Is there a way to do that?
Use querySelectorAll() and map():
const res = [...document.querySelectorAll("#breadcrumb li:not(:first-of-type)")].map(el => el.getAttribute("title")).join(" ")
console.log(res)
<div id="breadcrumb">
<ul>
<li title="One">One</li>
<li title="Two">Two</li>
<li title="Three">Three</li>
<li title="Four">Four</li>
</ul>
</div>
Using a little jquery i achieved this and it should solve your issues.
let list = [];
$('#breadcrumb li').each(function(i){
if(i !== 0) { list.push($(this).attr('title')); }
});
list.toString() //One,Two,Three,Four
The method you tried to use wont scale on a large list
Two minor remarks:
If you want to access the id=breadcrumb, you have to use #breadcrumb instead of .breadcrumb
There is no a tag in your HTML-code, therefore your querySelector won't give you any result
However, let's discuss a solution:
let listElements = document.querySelectorAll("#breadcrumbs li"); // get all list elements
listElements = Array.from(listElements); // convert the NodeList to an Array
listElements = listElements.filter((value, index) => index >= 1); // remove the first element
let titleAttributes = listElements.map(listElement => listElement.getAttribute("title")); // get the title attributes for every list elements. The result is an array of strings containing the title
console.log(titleAttributes.join(", ")); // concatenate the titles by comma
You can write the above statements in a single line:
Array.from(document.querySelectorAll("#breadcrumbs li"))
.filter((value, index) => index >= 1)
.map(listElement => listElement.getAttribute("title"))
.join(", ");
EDIT: I fix my answer, thanks to Barmar
something like that ?
const All_LI = [...document.querySelectorAll('#breadcrumb li')];
let a = ''
for (let i=1; i<All_LI.length; i++) { a += All_LI[i].title }
console.log('a-> ', a )
// .. or :
const b = All_LI.reduce((a,e,i)=>a+=(i>0)?e.title:'', '' )
console.log('b-> ', b )
<div id="breadcrumb">
<ul>
<li title="One">One</li>
<li title="Two">Two</li>
<li title="Three">Three</li>
<li title="Four">Four</li>
</ul>
</div>
this is probably an easy question for you guys but I'm very new to coding and can't figure out this. I have a code that I want to randomize the given choices in the questions, and I've found a script online that does that but it's not working. I don't know what the
// shuffle only elements that don't have "group" class
$ul.find("li[class!='single_question', 'question', 'title', 'text']").each(function() {
means so I tried to put all id that I don't need to randomize in it but it's still not working.
Can someone help me this please? Also is there anyway I can add choice "A", choice "B", choice "C", and choice "D" in front of each given options so even after the options(answers) are randomized, the A,B,C,D options will still be in order? Thank you. Here's the code:
HTML:
<!DOCTYPE html>
<html>
<body>
<script src="JQ.js"></script>
<script src="function.js"></script>
<link href="style.css" rel="stylesheet" />
<div id="quiz_container">
<ul class="quiz_container">
<li class="single_question" data-question-id="1" data-correct-answer="1">
<div class="question">
<h1 class="title">P.1 Grammar Review</h1>
<p class="text">1. "What is your name__"</p>
</div>
<ul class="options">
<li value="1">?</li>
<li value="2">.</li>
<li value="3">,</li>
</ul>
<div class="result"></div>
</li>
<li class="single_question" data-question-id="2" data-correct-answer="b">
<div class="question">
<p class="text">2. "Do you like the banana__"</p>
</div>
<ul class="options">
<li value="a">.</li>
<li value="b">?</li>
<li value="c">,</li>
</ul>
<div class="result"></div>
</li>
</div>
</body>
</html>
JS:
$(document).ready(function () {
/*
* shuffles the array
* #param {Array} myArray array to shuffle
*/
function shuffleArray(myArray) {
for (var i = myArray.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = myArray[i];
myArray[i] = myArray[j];
myArray[j] = temp;
}
return myArray;
}
var $ul, $li, li_content, li_list;
// find all lists to shuffle
$("#quiz_container > ul").each(function () {
$ul = $(this);
li_list = [];
// shuffle only elements that don't have "group" class
$ul.find("li[class!='single_question', 'question', 'title', 'text']").each(function () {
// add content to the array and remove item from the DOM
li_list.push($(this).html());
$(this).remove();
});
// shuffle the list
li_list = shuffleArray(li_list);
while (li_content = li_list.pop()) {
// create <li> element and put it back to the DOM
$li = $("<li />").html(li_content);
$ul.append($li);
}
});
$("#contact_div").show();
});
$(document).on('click', '.single_question .options li', function () {
// Save the question of the clicked option
question = $(this).parents('.single_question');
// Remove If Anyother option is already selected
question.find('.selected').removeClass('selected');
// Add selected class to the clicked li
$(this).addClass('selected');
// selected option value
selected_answer_value = $(this).attr("value");
// Value of correct answer from '.single-question' attribute
correct_answer_value = question.attr("data-correct-answer");
correct_answer_text = question.find('.options').find("li[value='" + correct_answer_value + "']").text();
if (correct_answer_value == selected_answer_value)
result = "<div class='correct'> Correct ! </div>";
else
result = "<div class='wrong'> Correct answer is -> " + correct_answer_text + "</div>";
// Write the result of the question
$(this).parents('.single_question').find('.result').html(result);
// Calculate the score
score_calculator();
});
/**
* It loops through every question and increments the value when "data-correct-answer" value and "option's value" are same
*/
function score_calculator() {
score = 0;
$('.single_question').each(function () {
question = $(this);
if (question.attr('data-correct-answer') == question.find('.selected').attr("value")) {
score++;
}
});
$('.correct_answers').html(score);
}
It looks like you're using jQuery, even though the question isn't tagged as such. If that's the case, you can use a code snippet written by Chris Coyier of CSS-Tricks called shuffle children.
Here's an example of the code in action.
$.fn.shuffleChildren = function() {
$.each(this.get(), function(index, el) {
var $el = $(el);
var $find = $el.children();
$find.sort(function() {
return 0.5 - Math.random();
});
$el.empty();
$find.appendTo($el);
});
};
$("ul.randomized").shuffleChildren();
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<h4>Static List:</h4>
<ul>
<li>First element</li>
<li>Second element</li>
<li>Third element</li>
<li>Fourth element</li>
</ul>
<h4>Randomized List:</h4>
<ul class="randomized">
<li>First element</li>
<li>Second element</li>
<li>Third element</li>
<li>Fourth element</li>
</ul>
In order to apply it to your own code, all you'd need to do is modify the CSS selector at the bottom of the jQuery snippet. In your case, ul.options might be a good choice.
Here are a couple of examples using your markup:
jsFiddle
Self-Contained HTML Doc
I am basically trying to check if my submenu has more than five list items, and if it does grab the remaining list item's and place them inside a new ul that is outside of the current parent ul using jquery. it gets complicated because of the structure of the list.
Here is the DOM structure:
<ul id="nav" class="se test">
<li id="menu1" class="page-1307 parent-menu parent">
<div class="nav-inner">
<a class="menulink" id="menuitem1" onclick="return false" href="#">test<span class="toggle"></span></a>
<ul id="ie1" class="plain">
<li class="parent-menu parent">test<span class="toggle"></span>
<div class="submenu-wrapper">
<ul class="plain">
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
</ul>
</div>
</li>
<li class="parent-menu parent">test<span class="toggle"></span>
<div class="submenu-wrapper">
<ul class="plain">
<li>test</li>
<li>test</li>
<li>test</li>
<li>test</li>
</ul>
</div>
</li>
</ul>
</div>
</li>
<li id="menu2" class="menulink page-7">
<div class="nav-inner">
test
</div>
</li>
</ul>
Basically i need to grab those remaining list items and place them in a new li.parent-menu.parent that includes the children div.sub-menu-wrapper and the ul.plain. the actual remaining list items would go inside the ul.plain of the new li.parent-menu. i hope thi makes since. i have been stuck on this for a day or two and unble to figure it out. any help would be greatly apprecitated, thank you.
This is what i am striving for, keep in mind it is dynamic.
you can:
Loop all ul in your document
foreach element count children
if found li number under an ul element is > 5
create a new list with the html of the required list
$(document).ready(function(){
$('.submenu-wrapper').each(function(){
var count_li=0;
var i=1;
$(this).children('ul').children('li').each(function(){
count_li++;
if(count_li>5 && i==1){
$(document.body).append('<ul id="newlist"></ul>');
$('#newlist').append($(this).nextUntil($(this).last()).andSelf());
i++;
}
});
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<ul id="nav" class="se test">
<li id="menu1" class="page-1307 parent-menu parent">
<div class="nav-inner">
<a class="menulink" id="menuitem1" onclick="return false" href="#">test<span class="toggle"></span></a>
<ul id="ie1" class="plain">
<li class="parent-menu parent">test<span class="toggle"></span>
<div class="submenu-wrapper">
<ul class="plain">
<li>test11</li>
<li>test12</li>
<li>test13</li>
<li>test14</li>
<li>test15</li>
<li>test16</li>
<li>test17</li>
</ul>
</div>
</li>
<li class="parent-menu parent">test<span class="toggle"></span>
<div class="submenu-wrapper">
<ul class="plain">
<li>test21</li>
<li>test22</li>
<li>test23</li>
<li>test24</li>
</ul>
</div>
</li>
</ul>
</div>
</li>
<li id="menu2" class="menulink page-7">
<div class="nav-inner">
test
</div>
</li>
</ul>
Here is the final answer I was looking for:
megaMenu: function(){
function addNewList(current, newItems) {
var newList = $('<li class="parent-menu parent newLi">');
var div = $('<div class="submenu-wrapper">');
newList.append(div);
var ul = $('<ul class="plain">');
div.append(ul);
for (var i = 0; i < newItems.length; i++) {
ul.append(newItems[i]);
}
current.after(newList);
return newList;
}
function splitLists() {
var allLists = $(".plain > li.parent-menu");
for (var i = 0; i < allLists.length; i++) {
var currentList = $(allLists[i]);
var items = currentList.find("li");
if (items.length > 5) {
var temp = [];
for (var j = 5; j < items.length; j++) {
temp.push($(items[j]));
if (temp.length == 5) {
currentList = addNewList(currentList, temp);
temp = [];
}
}
if (temp.length > 0) {
currentList = addNewList(currentList, temp);
}
}
}
}
splitLists();
}
After some clarification via comments it seems you are looking for something like this. I have commented the code to explain the logic behind the process:
// function for adding a new LI item.
function addNewList(current, newItems) {
// Create the new li node.
var newList = $('<li class="parent-menu parent">');
// Add the initial a link.
newList.append('test<span class="toggle"></span>');
// Create and append the submenu-wrapper div to our new list item.
var div = $('<div class="submenu-wrapper">');
newList.append(div);
// Create and append the new ul node to our submenu-wrapper div.
var ul = $('<ul class="plain">');
div.append(ul);
// Loop the 5 (or less) items that have been specified and add them to our new list.
for (var i = 0; i < newItems.length; i++) {
// Using append will move the elements that already exist in the original place.
ul.append(newItems[i]);
}
// Add our new list item to the DOM.
current.after(newList);
return newList;
}
// Base function to split the lists as required.
function splitLists() {
// Get all the lists that we want to process.
var allLists = $(".plain > li.parent-menu");
// Loop each list and process.
for (var i = 0; i < allLists.length; i++) {
var currentList = $(allLists[i]);
// Get the sub-items that we need to split.
var items = currentList.find("li");
// We only care about lists that are more than 5 items.
if (items.length > 5) {
// Create array to store the items that we want to move (any after first 5)
var temp = [];
// Start at the 6th item an start moving them in blocks of 5.
for (var j = 5; j < items.length; j++) {
// Add the item to move to our temp array.
temp.push($(items[j]));
// If we have 5 in our temp array then move them to new list.
if (temp.length == 5) {
// Move items with helper function.
currentList = addNewList(currentList, temp);
// Clear the temp array ready for the next set of items.
temp = [];
}
}
// If we have any spare ones that didn't get handle in the length == 5 check, then process them now.
if (temp.length > 0) {
currentList = addNewList(currentList, temp);
}
}
}
}
// Run the process.
splitLists();
Here is a working example
I want to append the <li> from one <ul> to another <ul> that's created on the fly. I want to group the list-items into new sub-lists based on their data-group attribute.
<ul id="sortable1">
<li data-group="A">test</li>
<li data-group="A">test1</li>
<li data-group="B">test2</li>
<li data-group="B">test3</li>
<li data-group="C">test4</li>
</ul>
Basically I'm trying to loop through this list and grap all <li> from each group, and then move it to another <ul>.
This is what I have so far, but I'm not getting the expected results. I have done this in Excel in the past but can't get it to work with jQuery.
var listItems = $("#sortable1").children("li");
listItems.each(function (idx, li) {
var product = $(li);
//grab current li
var str = $(this).text();
if (idx > 0) {
//append li
str += str;
if ($(this).data("group") != $(this).prev().data("group")) {
//I should be getting test and test1.
//but alert is only giving test1 test1.
alert(str);
//need to break into groups
//do something with groups
}
}
});
How about something like this:
$(function() {
var sortable = $("#sortable1"),
content = $("#content");
var groups = [];
sortable.find("li").each(function() {
var group = $(this).data("group");
if($.inArray(group, groups) === -1) {
groups.push(group);
}
});
groups.forEach(function(group) {
var liElements = sortable.find("li[data-group='" + group + "']"),
groupUl = $("<ul>").append(liElements);
content.append(groupUl);
});
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul id="sortable1">
<li data-group="A">test</li>
<li data-group="A">test1</li>
<li data-group="B">test2</li>
<li data-group="B">test3</li>
<li data-group="C">test4</li>
</ul>
<div id="content">
</div>
I hope I didn't misunderstand you.