Replacing <li> elements with result from an array - javascript

I have the following markup:
<ul class="category-top-navigation__group category-top-navigation__group--level-2 " data-category="jj-brands">
<li data-group="accessories">Scarf</li>
<li data-group="bottoms">Shorts</li>
<li data-group="tops">Polo</li>
<li data-group="tops">T-shirt</li>
<li data-group="bottoms">Jeans</li>
<li data-group="accessories">Sunglasses</li>
</ul>
I have made some JavaScript logic which I use to get all the <li> elements and sort them into a two-dimensional array dependent on the data-group.
This means that the sorting would contain the following list:
"<li data-group='accessories'>Scarf</li>"
"<li data-group='accessories'>Sunglasses</li>"
"<li data-group='bottoms'>Shorts</li>"
"<li data-group='bottoms'>Jeans</li>"
"<li data-group='tops'>Polo</li>"
"<li data-group='tops'>T-shirt</li>"
Now what I would like to do is to replace the already existing <li> elements inside the <ul> with the new sorted list. And this is where I am stuck.
CodePen Example Here

Replace the uls innerHTML using a joined Array created from the li-elements that is sorted on its elements using the data-group attribute, mapped to to strings from the elements outerHTML.
const ul = document.querySelector("ul");
ul.innerHTML = Array.from(ul.querySelectorAll("li"))
.sort( (a, b) => a.dataset.group.localeCompare(b.dataset.group) )
.map(v => v.outerHTML)
.join("");
<ul class="category-top-navigation__group category-top-navigation__group--level-2 " data-category="jj-brands">
<li data-group="accessories">Scarf</li>
<li data-group="bottoms">Shorts</li>
<li data-group="tops">Polo</li>
<li data-group="tops">T-shirt</li>
<li data-group="bottoms">Jeans</li>
<li data-group="accessories">Sunglasses</li>
</ul>

Working CodePen.
You need to append the li's to your ul element after clearing it, like :
var ul = document.querySelector('ul[data-category]');
//Clear your ul
ul.innerHTML = "";
for (i = 0; i < uniqueCategoryGroupNames.length; i++) {
sortedCategoryItems[i] = [ ];
for (j = 0; j < categoryItems.length; j++ ){
if (uniqueCategoryGroupNames[i] === categoryItems[j].getAttribute('data-group')) {
sortedCategoryItems[i][j] = categoryItems[j];
//Append your li's
ul.appendChild( sortedCategoryItems[i][j] );
}
}
}
}

Related

Randomize Multiple ul tags by class name using only JavaScript

I have multiple ul elements on my page and I need to add a class name to some and those with that class name need to randomize. I can do it by id but I can only have one id on a page so I can't do that. I need a JavaScript solution without JQuery. Any help is appreciated. Thank you.
Here is what I used to randomize it by id (it only does one ul though):
var thisUL = document.getElementById("myID");
for (var i = thisUL .children.length; i >= 0; i--) {
thisUL.appendChild(thisUL.children[Math.random() * i | 0]);
}
<ul id="myID">
<li>random1a</li>
<li>random1b</li>
<li>random1c</li>
</ul>
<ul id="myID">
<li>random2a</li>
<li>random3b</li>
<li>random4c</li>
</ul>
<ul id="myID">
<li>random3a</li>
<li>random3b</li>
<li>random3c</li>
</ul>
Each li would need to stay within its own ul.
First of all, you should use class attribute, then use getElementsByClassName() to target all the elements having the class. Then iterate them with for loop and you have the rest of the functionality:
var ulList = document.getElementsByClassName("myElement");
for (let j = 0; j < ulList.length; j++) {
var thisUL = ulList[j];
for (let i = thisUL.children.length; i >= 0; i--) {
thisUL.appendChild(thisUL.children[Math.random() * i | 0]);
}
}
<ul class="myElement">
<li>random1a</li>
<li>random1b</li>
<li>random1c</li>
</ul>
<ul class="myElement">
<li>random2a</li>
<li>random3b</li>
<li>random4c</li>
</ul>
<ul class="myElement">
<li>random3a</li>
<li>random3b</li>
<li>random3c</li>
</ul>

jQuery - Sort list into groups with headings, then alphabetically

I'm trying to sort a list into groups with headings in alphabetical order. So far I found a solution of the first step here: Use jQuery to sort a list into groups with headings
Then I want the headings to be sorted alphabetically. The nested lists should be sorted alphabetically so that it goes from this:
<ul id="list">
<li class="grouphead">Meat</li>
<li>
<ul>
<li>Lamb</li>
<li>Pork</li>
<li>Beef</li>
</ul>
</li>
<li class="grouphead">Fruit and Vegetables</li>
<li>
<ul>
<li>Orange</li>
<li>Banana</li>
<li>Cabbage</li>
</ul>
</li>
</ul>
to this
<ul id="list">
<li class="grouphead">Fruit and Vegetables</li>
<li>
<ul>
<li>Banana</li>
<li>Cabbage</li>
<li>Orange</li>
</ul>
</li>
<li class="grouphead">Meat</li>
<li>
<ul>
<li>Beef</li>
<li>Lamb</li>
<li>Pork</li>
</ul>
</li>
</ul>
Here's what I have so far: http://jsfiddle.net/z6j5t0k3/5/
<ul id="list">
<li>Lamb</li>
<li>Pork</li>
<li>Beef</li>
<li>Banana</li>
<li>Orange</li>
<li>Cabbage</li>
</ul>
var dict = {
}
$("#list li").each( function() {
var k = $(this).children(":first").attr('rel');
if ( dict.hasOwnProperty(k) == false ) {
dict[k] = [];
}
dict[k].push( $(this).html() );
} );
$("#list").empty();
function newList(nam) {
var r = "";
for ( c in dict[nam] ) {
r += "<li>" + dict[nam][c] + "</li>";
}
return r;
}
for ( nam in dict ) {
$("#list").append("<li class='grouphead'>" + nam + "</li>");
$("#list").append("<li><ul>" + newList(nam) + "</ul></li>");
}
function uCase(elem) {
return $.trim( $(elem).text().toUpperCase() )
}
function compareFirstLink(a, b) {
var A = uCase( $(a).first('a') ),
B = uCase( $(b).first('a') );
return (A > B) ? 1 : -1;
}
$(function () {
var $sortables = $("ul:has(div:first-child), li:not(.fixedOrder)");
$sortables.sort(compareFirstLink).each(function () {
this.parentNode.appendChild(this);
});
});
I used the code from this (Sorting nested lists) to try to sort the nested lists alphabetically but it didn't work.
Thank you!

How to createElement of list/images in separate rows?

So below I have the HTML code that is part of my draggable/droppable:
Drag from here:
<ul id="sortable1" class="dropBox connectedSortable">
<li class="ui-state-default">Word 1</li>
<li class="ui-state-default">Word 2</li>
<li class="ui-state-default">Word 3</li>
<li class="ui-state-default">Word 4</li>
</ul>
Drop a word onto each iamge: <br>
<ul class = "row">
<li id="drop1" class="dropZones images"><img src="image1.jpg"></li>
<li id="drop2" class="dropZones images"><img src="image2.jpg"></li>
</ul>
<ul class = "row">
<li id="drop_zone3" class="dropZones images"><img src="image3.jpg"></li>
<li id="drop_zone4" class="dropZones images"><img src="image4.jpg"></li>
</ul>
</div>
I am trying to create this using document.createElement() etc. But am having difficulty doing this efficiently.
The purpose of the rows (in above code) are for formatting (using bootstrap4), since there are 6 pictures total in my array, and I want 2 rows of 3.
Below, I have an array that holds all the images' src's. This array is passed into the function. I'm able to create one row/ul, with all of the li's/images inside. But I want to be able to create what I have above, with as little hard coding as possible and as efficiently as possible.
I have:
function createType3(arr)
{
var count = 0;
var length = arr.length;
var list = document.createElement("ul");
list.classList.add("row");
for (var i = 0; i < length; i++)
{
//create list and associated ids and classes
var listPiece=document.createElement("li");
listPiece.classList.add("dropZones","images","list-inline");
listPiece.setAttribute("id","dropZone");
//create image tags and append
var imageSRC = document.createElement("IMG");
imageSRC.setAttribute("src",arr[i]);
listPiece.appendChild(imageSRC);
list.appendChild(listPiece);
}
return list;
}
I'm having trouble doing this, thank you.
You could create a document fragment and add list elements to it. Create a new list whenever i % 3 is zero. Make that 3 an argument so that you can use the function also for lists of any other number of entries:
function createType(arr, groupSize = 3) {
var lists = document.createDocumentFragment(),
list;
for (var i = 0; i < arr.length; i++) {
if (i % groupSize === 0) {
list = document.createElement("ul");
list.classList.add("row");
lists.appendChild(list);
}
//create list and associated ids and classes
var listPiece = document.createElement("li");
listPiece.classList.add("dropZones","images","list-inline");
listPiece.setAttribute("id","dropZone");
//create image tags and append
var imageSRC = document.createElement("IMG");
imageSRC.setAttribute("src", arr[i]);
listPiece.appendChild(imageSRC);
list.appendChild(listPiece);
}
return lists;
}
You could call it like this:
var frag = createType(["img1.png","img2.png","img3.png","img4.png"], 3);
document.body.appendChild(frag); // add it somewhere in your HTML page

How to append <li> to a <ul> on button click

How to append <li> to a <ul> on a button click.
I have tried below script, but want to have a number appended to the end of <li>. Like item 0, item 1, item 2, etc..
var list = document.getElementById("list");
var add = document.getElementById('addElem');
add.addEventListener('click', function() {
var itemsByTagName = document.getElementsByTagName("li");
list.innerHTML += '<li>item</li>'
});
<ul id="list">
<li>item
</li>
</ul>
<button id="addElem">Add</button>
Here is a example to get started.
Note: For production use you might need to handle the variable i through server/session/local storage variable.
var i = 1;
var list = document.getElementById("list");
var add = document.getElementById('addElem');
add.addEventListener('click', function() {
var itemsByTagName = document.getElementsByTagName("li");
list.innerHTML += '<li>item ' + i++ + '</li>'
});
<ul id="list">
<li>item
</li>
</ul>
<button id="addElem">Add</button>

jQuery find data attributes with one datakey and multiple values

I want to retrive all the objects with one datakey and multiple values, for QuickSand:
<ul>
<li data-company="Microsoft">Steve</li>
<li data-company="Google">Jobs</li>
<li data-company ="Facebook">Michael</li>
<li data-company ="Google">Richard</li>
<li data-company ="Facebook">Tim</li>
</ul>
How can i retreve all the li items with data-company Microsoft and Google (these two values are in a array) like this:
var itemes = $('ul').find('li[data-comapany={"Microsoft","Google"}]');
Thank you.
you could create an array of the required companies, and check for each li if the data is contained in that array:
var companies = ["Microsoft", "Google"];
$(function() {
var items = $('ul li').filter(function() {
return $.inArray($(this).data("company"), companies) > -1;
});
items.css({
"position": "relative",
"margin-left": "25px"
});
console.log(items);
});
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<ul>
<li data-company="Microsoft">Steve</li>
<li data-company="Google">Jobs</li>
<li data-company="Facebook">Michael</li>
<li data-company="Google">Richard</li>
<li data-company="Facebook">Tim</li>
</ul>
You could filter it:
var itemes = $('ul').find('li').filter(function(){
return $(this).data('company').match(/Microsoft|Google/);
});
-DEMO-
To handle case for LI without any data-company set, you should use:
var itemes = $('ul').find('li').filter(function(){
var data = $(this).data('company');
return data ? data.match(/Microsoft|Google/) : null;
});
You can also combine selectors:
var items = $("[data-company*='Microsoft'], [data-company*='Google']");
jsFiddle
You could do it like this:
var companies = ['Google', 'Microsoft', 'Waffle House'];
companies.forEach(function(company, index) {
companies[index] = "li[data-company='" + company + "']";
});
$('ul').find(companies.join(',')).css('background', 'red');

Categories

Resources