Nested unordered lists from nested array (recursive) - javascript

I have a bit of code that loops through nested array (it can be unlimited in depth) and I am trying to generate a treelike structure from it.. of basically nested unordered lists..
Here is my fiddle http://jsfiddle.net/aj9TC/6/
I collect items names in a function like this:
function get_list( a ) {
for (var i = 0; i < a.length; i++) {
console.log( i + "---" + a[i].name );
$(".mod-list ul").append('<li>' + a[i].name + '</li>');
get_list( a[i].group );
}
}
get_list( mods.group );
My sample html is simple
<h4>Nested List</h4>
<div class="mod-list">
<ul class="list">
</ul>
</div>
I currently append all items as li in a single unordered list,, but I need to create nested unordered lists that reflect the array nesting accurately.
Can someone help me out with this please.
Thanks!

What about this:
function get_list( a, $parent ) {
var newUl = $("<ul></ul>");
for (var i = 0; i < a.length; i++) {
if (a[i]) {
newUl.append('<li>' + a[i].name + '</li>');
if (a[i].group)
get_list( a[i].group, newUl );
}
}
$parent.append(newUl);
}
get_list( mods.group, $(".mod-list"));
Here's a working fiddle: http://jsfiddle.net/aj9TC/7/

Another solution that doesn't leave empty <ul>'s
I also like to build up all my html and add it to the DOM once, instead of adding lots of little snippets.
function get_list( a, str ) {
str += '<ul>';
for (var i = 0; i < a.length; i++) {
str += '<li>' + a[i].name;
if (a[i].group && a[i].group.length) str += get_list( a[i].group, '' );
str += '</li>';
}
str += '</ul>';
return str;
}
$(".mod-list").append(get_list( mods.group, ''));
http://jsfiddle.net/aj9TC/8/

Here's an approach that also builds all the html in array of strings and only does one append when done. Join array when ready to insert.
$(function(){
var $list=$(get_list(mods.group,[]).join('')).addClass('list')
$('.mod-list').append($list)
});
function get_list(data, strArray) {
strArray.push('<ul>');
$.each(data, function(i, val) {
strArray.push('<li>' + val.name);
if (val.group) {
get_list(val.group,strArray);
}
strArray.push('</li>');
});
strArray.push('</ul>');
return strArray;
}
DEMO

Related

How can I get multiple unique values from a JSON with JQuery?

I have this JSON:
var dataM = '[{"category":"cat01","subcategory":"subcat01"},{"category":"cat01","subcategory":"subcat01"},{"category":"cat01","subcategory":"subcat03"}, {"category":"cat01","subcategory":"subcat03"},{"category":"cat01","subcategory":"subcat02"},{"category":"cat02","subcategory":"subcat04"},{"category":"cat02","subcategory":"subcat04"},{"category":"cat02","subcategory":"subcat02"},{"category":"cat01","subcategory":"subcat05"}]';
I want to get unique values and build an HTML unordered list structure , so I make this:
var dataM = '[{"category":"cat01","subcategory":"subcat01"},{"category":"cat01","subcategory":"subcat01"},{"category":"cat01","subcategory":"subcat03"}, {"category":"cat01","subcategory":"subcat03"},{"category":"cat01","subcategory":"subcat02"},{"category":"cat02","subcategory":"subcat04"},{"category":"cat02","subcategory":"subcat04"},{"category":"cat02","subcategory":"subcat02"},{"category":"cat01","subcategory":"subcat05"}]';
var dataJSON = JSON.parse(dataM);
var arrayM = []; var html='';
for(i = 0; i< dataJSON.length; i++){
if(arrayM.indexOf(dataJSON[i].category) === -1){
arrayM.push(dataJSON[i].category);
}
}
html += '<ul>';
for(i = 0; i< arrayM.length; i++){
html += '<li>'+arrayM[i]+'</li>';
}
html += '</ul>';
$("#list").html(html);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="list"></div>
The problem is I only get the unique category values:
And I want to include the unique subcategory values of each category like this:
How can I fix it? I'd like to receive your help.
Instead off using an array, I'd recommend using an object so you can set each category on the key, push each subcategory into an array.
Then, if you only keep the unique subcats, you can use that array to show them:
var dataM = '[{"category":"cat01","subcategory":"subcat01"},{"category":"cat01","subcategory":"subcat01"},{"category":"cat01","subcategory":"subcat03"}, {"category":"cat01","subcategory":"subcat03"},{"category":"cat01","subcategory":"subcat02"},{"category":"cat02","subcategory":"subcat04"},{"category":"cat02","subcategory":"subcat04"},{"category":"cat02","subcategory":"subcat02"},{"category":"cat01","subcategory":"subcat05"}]';
var dataJSON = JSON.parse(dataM);
var arrayM = {};
var html='';
for(i = 0; i < dataJSON.length; i++) {
if (!arrayM[dataJSON[i].category]) {
arrayM[dataJSON[i].category] = [];
}
arrayM[dataJSON[i].category].push(dataJSON[i].subcategory);
}
html += '<ul>';
for (let [category, subcategorys] of Object.entries(arrayM)) {
html += '<li>'+category+'</li>';
html += '<ul>';
subcategorys = subcategorys.filter((v, i, a) => a.indexOf(v) === i);
for (i = 0; i < subcategorys.length; i++) {
html += '<li>'+subcategorys[i]+'</li>';
}
html += '</ul>';
}
html += '</ul>';
$("#list").html(html);
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<div id="list"></div>
For this you can make use of reducer Reducer
By making use of reducer you can run filter and map together.
var dataM = [{"category":"cat01","subcategory":"subcat01"},{"category":"cat01","subcategory":"subcat01"},{"category":"cat01","subcategory":"subcat03"}, {"category":"cat01","subcategory":"subcat03"},{"category":"cat01","subcategory":"subcat02"},{"category":"cat02","subcategory":"subcat04"},{"category":"cat02","subcategory":"subcat04"},{"category":"cat02","subcategory":"subcat02"},{"category":"cat01","subcategory":"subcat05"}];
result = dataM.reduce(function (r, a) {
r[a.category] = r[a.category] || [];
r[a.category].push(a.subcategory);
return r;
}, Object.create(null));
html = '<ul>';
Object.keys(result).map(keys => {
html += "<li>" + keys + ":"
html += "<ul>"
result[keys].map( data => {
html += "<li>"+data+"</li>"
})
html+="</ul>"
});
html +="</ul>"
$("#list").html(html)
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div id="list"></div>

Display message if array is empty

I'm displaying favorites from localStorage on a page and I'd like to display a message for people that don't have any favorites yet.
This is the div that displays the list which I'd like to repurpose to display the message below when there are no favorites:
<div id='favorites'></div>
And here is the JavaScript that normally shows the favorites:
var options = Array.apply(0, new Array(localStorage.length)).map(function (o, i){
return localStorage.key(i);
});
function makeUL() {
var LIs = '';
var noFavs = 'Hmm, you must\'ve not favorited anything yet. Maybe you\'ll like this one.';
var len = options.length;
if (len === 0) {
document.getElementById('nofavorites').innerHTML = noFavs;
} else {
for (i = 0; i < len; i += 1) {
LIs += '<li>' + options[i] + '</li>';
}
return '<ul>' + LIs + '</ul>';
}
}
document.getElementById('favorites').innerHTML = makeUL();
Right now it just shows undefined.
This is in your html:
<div id='favorites'></div>
<div id='nofavorites'></div>
Your javascript:
var options = Array.apply(0, new Array(localStorage.length)).map(function (o, i){
return localStorage.key(i);
});
function loadFavoriteHTML() {
var favoriteHtml = '';
var noFavs = 'Hmm, you must\'ve not favorited anything yet. Maybe you\'ll like this one.';
var len = options.length;
// Clear html lists
document.getElementById('favorites').innerHTML = '';
document.getElementById('nofavorites').innerHTML = '';
if (len === 0) {
document.getElementById('nofavorites').innerHTML = noFavs;
} else {
for (var i = 0; i < len; i++) {
favoriteHtml+= '<li>' + options[i] + '</li>';
}
var ulHtml= '<ul>' + favoriteHtml+ '</ul>';
document.getElementById('favorites').innerHTML = ulHtml;
}
}
loadFavoriteHTML();
Your code is show undefine because when you dont have favorites list you dont return anything in you makeUI function, and by default the return value is undefined in a function if you dont have return.
I changed your code to set the UI in the function because you edit 2 different div. there is others way to do it. this is a one way.
It's because the makeUL function doesn't return any value when there's no element in the options array.
You'll have to choose between: updating your element inside your function
OR getting the value to insert inside your HTML element returned by your function. But you shouldn't do both.
You might want to change your code into something like this?
var options = Array.apply(0, new Array(localStorage.length)).map(function (o, i) {
return localStorage.key(i);
});
function makeUL() {
var LIs = '';
var noFavs = 'Hmm, you must\'ve not favorited anything yet. Maybe you\'ll like this one.';
var len = options.length;
if (len === 0) {
document.getElementById('favorites').innerHTML = noFavs;
} else {
for (var i = 0; i < len; i += 1) {
LIs += '<li>' + options[i] + '</li>';
}
document.getElementById('favorites').innerHTML = '<ul>' + LIs + '</ul>';
}
}
makeUL();
Plus, you're targeting a nofavorites element that doesn't exist in your example.

For Loop returning all in string Javascript

I'm using a for loop to return all the values within an array … at the moment it's returning them all in a string but I want them to return as individual values so I can do stuff with each one … heres my code so far…
function generateSelectors(product) {
var i;
if( product.attrs.available == false) {
$('.variant-selectors, .buy-button').hide();
} else {
for (i = 0; i < product.attrs.options.length; i++) {
var options = '<p>' + product.attrs.options[i].values + '</p>';
}
}
$('.html').html(options);
}
Outputting as <div class="html"><p>3(36),4(37),5(38),6(39),7(40)</p></div>
What I'd like is …
<div class="html">
<p>3(36)</p>
<p>4(37)</p>
etc…
</div>
Thanks in advance, sure this is relatively easy.
Need to do like below:-
function generateSelectors(product) {
var i;
var options =''; //define variable outside of loop
if( product.attrs.available == false) {
$('.variant-selectors, .buy-button').hide();
} else {
for (i = 0; i < product.attrs.options.length; i++) {
$.each(product.attrs.options[i].values ,function(key,val){//iterate over array
options += '<p>' + val + '</p><br/>'; //append each value to variable
});
}
}
$('.html').html(options); // add full-data as HTML to element
}
You might want to look at Array.prototype.map - it's a functional way of doing exactly what you're trying to do with a manual for loop
function generateSelectors(product) {
if (product.attrs.available == false) {
$('.variant-selectors, .buy-button').hide();
else
$('.html').html(
product.attrs.options.map(o => '<p>' + o.values + '</p>').join('')
)
}

Add certain values from JSON object to javascript array

Update: I've tried the suggestions in the comments and it's still not working. I really have no idea why. I've consolidated it to a single loop and fixed the syntax errors noted. Here's the code as it looks now:
$(function() {
$("#json-one").change(function() {
var $dropdown = $(this);
$.getJSON("washroutines.json", function(data) {
var vals = [];
var $jsontwo = $("#json-two");
$jsontwo.empty();
for (var i = 0; i < data.length; i++){
if (data[i].make === $dropdown.val()) {
$jsontwo.append("<option value=\"" + data[i].model + "\">" + data[i].model + "</option>");
}
}
});
});
});
Any additional help would be much appreciated!
Original question:
I'm trying to create dependent drop down menus using a json object, and I'm having trouble getting the second menu to populate based on the first. When the first menu changes, the second goes to a bunch of "undefined"s.
$.getJSON("washroutines.json", function(data) {
var vals = [];
for (i = 0; i < data.length; i++){
if (data.make = $dropdown.val()) {
vals.push(data.model);
}
}
var $jsontwo = $("#json-two");
$jsontwo.empty();
for (i = 0; i < vals.length; i++){
$jsontwo.append("<option value\"" + vals[i] + "\">" + vals[i] + "</option>");
}
Please use small words when explaining things to me, I'm new at this!
contents of the JSON:
[{"make":"Maytag","model":"Bravos","prewashCycle":"Whitest Whites"},
{"make":"Maytag","model":"Awesome","prewashCycle":"Awesome Whitest Whites"},
{"make":"Whirlpool","model":"Cabrio","prewashCycle":"Extra Heavy"},
{"make":"Kenmore","model":"Elite","prewashCycle":"Awesome"}]
Try changing your for loop for this
for (var i = 0; i < data.length; i++){
if (data[i].make === $dropdown.val()) {
vals.push(data[i].model);
}
}

What Is The Error In JavaScript code

I am trying to click on links to add it to select with checking if there is the item was not in list before menu but It seems loop part has some issue.
JavaScript code
$(document).ready(function() {
$('.link').click(function(event) {
var this_item_was_not_in_list = true;
var item =$(this).text();
for (var i = 0; i < $('#list').length; i++) {
if ($('#list').options[i].text == item) { this_item_was_not_in_list = false; break;};
};
if (this_item_was_not_in_list) {$('#list').append('<option>' + item + '</option>')};
});
});
HTML Code
Bread
Suger
Tea
<select id="list">
</select>
There are numerous ways to simplify this using jQuery methods.
One example:
$('.link').click(function(event) {
var item = $(this).text();
if(!$('#list option[value=' + item +']').length){
$('#list').append('<option value="' + item +'">' + item + '</option>');
}
});
Instead of using your for loop can easily iterate over a collection of elements using each() which exposes the index and the element
Where you are doing:
for (var i = 0; i < $('#list').length; i++) {
You should be doing:
for (var i = 0; i < $('#list option').length; i++) {
if ($('#list').options[i].text == item)
Aren't some parenthesis missing?
if ($('#list').options[i].text() == item)
The problen is here:
$('#list').options[i].text == item
That is not the way to get option elements from the select element.
Try this:
$('#list').find('options:nth(' + i + ')')).text() == item
Use the following code. Here's the jsfiddle for this.
$(document).ready(function() {
$('.link').click(function(event) {
var this_item_was_not_in_list = true;
var clickedItemName =$(this).text();
var listLength = $('#list option').length;
for (i=0; i<listLength ; i++)
{
if ($('#list option')[i].value == clickedItemName)
{
this_item_was_not_in_list = false;
break;
}
}
if (this_item_was_not_in_list)
{
$('#list').append('<option>' + clickedItemName + '</option>');
}
});
});
<html>
Bread
Sugar
Tea
<select id="list"></select>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
</html>

Categories