Display html from JS array - javascript

I am working on displaying an array of HTML elements from JavaScript that looks like this:
Here is my code:
function createOrderedList(items) {
var ol = document.createElement("ol");
items.forEach(function(item) {
ol.appendChild(createListItem(item));
});
return ol;
}
function createListItem(item) {
var li = document.createElement("li");
li.textContent = item;
return li;
}
var array = ["a", "b", "c", "d", "e"];
var list = array.reduceRight(function(p, c) {
var el = createOrderedList([c]);
if (p == null) {
p = el;
} else {
el.appendChild(p);
}
return el;
}, null);
document.querySelector(".content").appendChild(list);
<div class='content'></div>
I want it to look like the picture , for now I have something like this :
https://jsfiddle.net/ys0fp5bd/
I want make to make that the first one is equal the last one and the each next li is equal on the same level .

Related

Create a menu tree using JavaScript?

I have an requirement to create a tree structure menu from a . separated string array.
My out put should be like following
A
A1
A2
A3
B1
B2
B
B1
B2
B3
B4
C
C1
C2
C4
I am trying to implement that with the following script
<script>
function fnAppend(param) {
var cWin=window.open("","Categories","width=600,height=800,scrollbars=yes");
var array = ['A.A1.A2', 'A.A1.A3', 'A.B1.B2','C.C1.C2','B.B1.B2','B.B1.B3.B4','C4'],
tree = [],
levels = [tree],
last = [];
array.forEach(s => {
var temp = s.split('.');
temp.forEach((name, i) => {
if (last[i] === name) return;
levels[i].push({ name, children: levels[i + 1] = [] });
});
last = temp;
});
function traverse(arr) {
for (const branch of arr) {
console.log('Mother:', branch.name);
var ul=document.createElement('ul');
var li=document.createElement('li');
li.innerHTML="<a href=''>"+branch.name+"</a>";
ul.appendChild(li);
if (Array.isArray(branch.children) && branch.children.length > 0) {
console.log('Children:', branch.children.map(i => i.name).join(', '));
traverse(branch.children);
}
}
var list = document.createElement('div');
list.appendChild(ul);
try {
cWin.document.body.appendChild(list);
} catch (err) {
if (list.outerHTML) {
cWin.document.body.innerHTML = list.outerHTML;
} else {
console.log(err.name);
}
}
}
traverse(tree);
}
</script>
</head>
<body>
<ul id="mylist">
</ul>
<input type="button" value="Append child" onclick="fnAppend('test')" />
</body>
Using above script I am getting the following output
A3
B2
B1
C2
C1
B4
B3
B1
C4
Please help me to format the output.
Many thanks in advance.
Regards,
Pankaj
You could create tree and build a nested list with items.
function buildList(tree, target) {
var ul = document.createElement('ul');
tree.forEach(node => {
var li = document.createElement('li');
li.appendChild(document.createTextNode(node.name));
node.children.length && buildList(node.children, li);
ul.appendChild(li);
});
target.appendChild(ul);
}
var array = ['A.A1.A2', 'A.A1.A3', 'A.B1.B2','C.C1.C2','B.B1.B2','B.B1.B3.B4','C4'],
tree = [];
array.forEach(s => s.split('.').reduce((t, name) => {
var temp = t.find(o => o.name === name);
if (!temp) {
t.push(temp = { name, children: [] });
}
return temp.children;
}, tree));
console.log(tree);
buildList(tree, document.body);
A different approach wich works only if pop ups are allowed.
function open() {
var cWin = window.open("", "Categories", "width=600,height=800,scrollbars=yes");
cWin.document.write(buildList(tree).outerHTML);
}
function buildList(tree) {
if (!tree.length) return;
var ul = document.createElement('ul');
tree.forEach(node => {
var li = document.createElement('li'),
children = buildList(node.children);
li.appendChild(document.createTextNode(node.name));
if (children) li.appendChild(children);
ul.appendChild(li);
});
return ul;
}
var array = ['A.A1.A2', 'A.A1.A3', 'A.B1.B2','C.C1.C2','B.B1.B2','B.B1.B3.B4','C4'],
tree = [];
array.forEach(s => s.split('.').reduce((t, name) => {
var temp = t.find(o => o.name === name);
if (!temp) {
t.push(temp = { name, children: [] });
}
return temp.children;
}, tree));
console.log(tree);
<button onclick="open()">popup</button>

Recursion with DOM in JavaScript

I am learning JavaScript and I was trying to solve a question given at https://javascript.info/modifying-document#create-a-tree-from-the-object.
The question was to create a nested ul/li from the nested object given.
The following is my code:
let data =
{
"Fish": {
"trout": {},
"salmon": {}
},
"Tree": {
"Huge": {
"sequoia": {},
"oak": {}
},
"Flowering": {
"redbud": {},
"magnolia": {}
}
}
};
function createTree(data,key=null,parent_element=document.body){
if(Object.keys(data).length){
if(key){
li = document.createElement('li');
li.textContent = key;
li = parent_element.append(li);
}
ul = document.createElement('ul');
parent_element.append(ul);
for(let key in data){
createTree(data[key],key,ul);
}
return
}
li = document.createElement('li');
li.textContent = key;
parent_element.append(li);
return;
}
createTree(data);
This produces the following output
while the expected output is the following
What is wrong with my code? I can't find anything wrong with my logic.
There is nothing wrong with your logic. The problem is, you forgot to put a var declaration before your ul variable in your createTree function. Add var before it and your code works. (You should ALWAYS declare variables with var, let, or const or things can get weird.)
let data = {
"Fish": {
"trout": {},
"salmon": {}
},
"Tree": {
"Huge": {
"sequoia": {},
"oak": {}
},
"Flowering": {
"redbud": {},
"magnolia": {}
}
}
};
function createTree(data, key = null, parent_element = document.body) {
var li;
if (Object.keys(data).length) {
if (key) {
li = document.createElement('li');
li.textContent = key;
li = parent_element.append(li);
}
var ul = document.createElement('ul');
parent_element.append(ul);
for(let key in data){
createTree(data[key], key, ul);
}
return;
}
li = document.createElement('li');
li.textContent = key;
parent_element.append(li);
return;
}
createTree(data);
Here's a quick breakdown of the different ways to declare variables in javascript and what each one means:
// Creates a global variable.
myVar1 = 1;
// Creates a variable within the scope you're currently in. It's "hoisted"
// to the top of the scope you're currently in, so if you declare a var in
// the middle of a function, it gets pulled to the very top when your code
// is executed.
var myVar2 = 2;
// Declares a variable that is not hoisted.
let myVar3 = 3;
// Declares a constant that cannot be reassigned.
const myVar4 = 4;
The reason your implementation failed is because ul became a global variable which caused your function to not return a desirable result.
let data = {
"Fish": {
"trout": {},
"salmon": {}
},
"Tree": {
"Huge": {
"sequoia": {},
"oak": {}
},
"Flowering": {
"redbud": {},
"magnolia": {}
}
}
};
function createTree(data, key = null, parent_element = document.body) {
if (Object.keys(data).length) {
let ul = document.createElement('ul');
if (key) {
li = document.createElement('li');
li.textContent = key;
li = parent_element.append(li);
}
ul = document.createElement('ul');
parent_element.append(ul);
for (let key in data) {
createTree(data[key], key, ul);
}
return
}
li = document.createElement('li');
li.textContent = key;
parent_element.append(li);
return;
}
createTree(data);
You need to create let ul = document.createElement('ul'); then need to append <li> was creating issue...

javascript remove item from array, if an item already existing in array

following adds items to array:
var arrayOptions = [];
function AddToFilterOptionList(mode) {
arrayOptions.push(mode);
}
remove item from array:
function RemoveFromFilterOptionList(mode) {
var index = arrayOptions.indexOf(mode);
if (index !== -1) {
arrayOptions.splice(index, 1);
}}
for example if i call
AddToFilterOptionList('APPLE') - APPLE should be added to array.
If i again call
AddToFilterOptionList('APPLE+FRUIT') - it should remove the the item 'APPLE' from array arrayOptions and should add APPLE+FRUIT
Any time only one word that starts with APPLE can be in array.
How to find the word like 'APPLE' in javascript.
I tried with Match() which returns the matching word. IndexOf() returns 1 only if whole word is match but not start of word.
Cycle through the Array and then use the startsWith method.
void AddToFilterOptionList(String mode) {
for (i=0; i<arrayOptions.length; i++) {
if (mode.startsWith(arrayOptions[i] == 1)) {
array[i] = mode;
return; // found, so return
}
}
arrayOptions.push(mode); // should only get here if string did not exist.
}
You need to split by + characted and then loop over produced array to add/remove all items:
var arrayOptions = [];
function AddToFilterOptionList(mode) {
mode.split(/\+/g).forEach(function(el) {
var index = arrayOptions.indexOf(el);
if (index !== -1) {
arrayOptions.splice(index, 1);
}
else {
arrayOptions.push(el);
}
});
}
function RemoveFromFilterOptionList(mode) {
var index = arrayOptions.indexOf(mode);
if (index !== -1) {
arrayOptions.splice(index, 1);
}
}
AddToFilterOptionList('APPLE');
document.write('<p>' + arrayOptions); // expect: APPLE
AddToFilterOptionList('APPLE+FRUIT');
document.write('<p>' + arrayOptions); // expect: FRUIT
AddToFilterOptionList('APPLE+FRUIT+CARROT');
document.write('<p>' + arrayOptions); // expect: APPLE,CARROT
This will work assuming the 'this+that' pattern is consistent, and that we only care about the starting item.
http://jsbin.com/gefasuqinu/1/edit?js,console
var arr = [];
function remove(item) {
var f = item.split('+')[0];
for (var i = 0, e = arr.length; i < e; i++) {
if (arr[i].split('+')[0] === f) {
arr.splice(i, 1);
break;
}
}
}
function add(item) {
remove(item);
arr.push(item);
}
UPDATE:
function add (array, fruits) {
var firstFruit = fruits.split('+')[0]
var secondFruit = fruits.split('+')[1]
var found = false
var output = []
output = array.map(function (item) {
if (item.indexOf(firstFruit) > -1) {
found = true
return fruits
}
else return item
})
if (! found) {
array.push(fruits)
}
return output
}
var fruits = []
add(fruits, 'APPLE')
fruits = add(fruits, 'APPLE+GRAPE')
console.log(fruits[0]) // 'APPLE+GRAPE'
fruits = add(fruits, 'APPLE')
console.log(fruits[0]) // 'APPLE'
Try this, the code is not optimised though :P
<html>
<head>
<script src = "jquery-1.10.2.min.js"></script>
<script type = "text/javascript">
var itemList = [];
function addItem()
{
var item = $('#item').val();
if(item != '' || item != 'undefined')
{
if(itemList.length == 0)
itemList.push(item);
else
{
for(i=0;i<itemList.length;i++)
{
var splittedInputItems = [];
splittedInputItems = item.split("+");
var splittedListItems = [];
splittedListItems = itemList[i].split("+");
if(splittedListItems[0] == splittedInputItems[0])
{
itemList.splice(i,1);
itemList.push(item);
return;
}
}
itemList.push(item);
}
}
}
</script>
</head>
<body>
<input id="item" type = "text"/>
<input type = "button" value="Add" onclick="addItem()">
</body>
</html>
let items = [1, 2, 3, 2, 4, 5, 2, 7];
let item = 2;
for (let i = 0; i < items.length; i++) {
if (items[i] === item) {
items.splice(i, 1);
i = i - 1;
}
}
If you want to remove the element '2' from items array, it is a way.

JSON menu alphabetical order

Based on this tutorial i made JSON menu. And now items sorted by id, but i need sort them alphabetically and can't understand how to do that. Not sure if array.sort(); will help in my case
Here is JS code:
var builddata = function () {
var source = [];
var items = [];
for (i = 0; i < data.length; i++) {
var item = data[i];
var label = item["text"];
var parentid = item["parentid"];
var id = item["id"];
if (items[parentid]) {
var item = { parentid: parentid, label: label, item: item };
if (!items[parentid].items) {
items[parentid].items = [];
}
items[parentid].items[items[parentid].items.length] = item;
items[id] = item;
}
else {
items[id] = { parentid: parentid, label: label, item: item };
source[id] = items[id];
}
}
return source;
}
var source = builddata();
var buildUL = function (parent, items) {
$.each(items, function () {
if (this.label) {
var li = $("<li>" + this.label + "</li>");
li.appendTo(parent);
if (this.items && this.items.length > 0) {
var ul = $("<ul></ul>");
ul.appendTo(li);
buildUL(ul, this.items);
}
}
});
}
var ul = $("<ul></ul>");
ul.appendTo("#jqxMenu");
buildUL(ul, source);
HTML:
<div id='jqxMenu'>
</div>
Here is JSFIDDLE
source.sort(function(a, b){
if(a.text < b.text) return -1;
if(a.text > b.text) return 1;
return 0;
})
...is the basis. However, recursive implementation is needed in this case I suppose.
Here: jsfiddle
Try sort the source u return
return source.sort();
See: DEMO

Find an element in an array recursively

I have an array of objects. Every object in the array has an id and an item property that is an array containing other object. I need to be able to find an element in an array by id. Here is a sample of what I have done so far, but the recursive function is always returning undefined.
How can I quit the function and return the item when I have called the function recursively several times?
$(function () {
var treeDataSource = [{
id: 1,
Name: "Test1",
items: [{
id: 2,
Name: "Test2",
items: [{
id: 3,
Name: "Test3"
}]
}]
}];
var getSubMenuItem = function (subMenuItems, id) {
if (subMenuItems && subMenuItems.length > 0) {
for (var i = 0; i < subMenuItems.length; i++) {
var item;
if (subMenuItems[i].Id == id) {
item = subMenuItems[i];
return item;
};
getSubMenuItem(subMenuItems[i].items, id);
};
};
};
var searchedItem = getSubMenuItem(treeDataSource, 3);
alert(searchedItem.id);
});
jsFiddle
You should replace
getSubMenuItem(subMenuItems[i].items, id);
with
var found = getSubMenuItem(subMenuItems[i].items, id);
if (found) return found;
in order to return the element when it is found.
And be careful with the name of the properties, javascript is case sensitive, so you must also replace
if (subMenuItems[i].Id == id) {
with
if (subMenuItems[i].id == id) {
Demonstration
Final (cleaned) code :
var getSubMenuItem = function (subMenuItems, id) {
if (subMenuItems) {
for (var i = 0; i < subMenuItems.length; i++) {
if (subMenuItems[i].id == id) {
return subMenuItems[i];
}
var found = getSubMenuItem(subMenuItems[i].items, id);
if (found) return found;
}
}
};
I know its late but here is a more generic approach
Array.prototype.findRecursive = function(predicate, childrenPropertyName){
if(!childrenPropertyName){
throw "findRecursive requires parameter `childrenPropertyName`";
}
let array = [];
array = this;
let initialFind = array.find(predicate);
let elementsWithChildren = array.filter(x=>x[childrenPropertyName]);
if(initialFind){
return initialFind;
}else if(elementsWithChildren.length){
let childElements = [];
elementsWithChildren.forEach(x=>{
childElements.push(...x[childrenPropertyName]);
});
return childElements.findRecursive(predicate, childrenPropertyName);
}else{
return undefined;
}
}
to use it:
var array = [<lets say an array of students who has their own students>];
var joe = array.findRecursive(x=>x.Name=="Joe", "students");
and if you want filter instead of find
Array.prototype.filterRecursive = function(predicate, childProperty){
let filterResults = [];
let filterAndPushResults = (arrayToFilter)=>{
let elementsWithChildren = arrayToFilter.filter(x=>x[childProperty]);
let filtered = arrayToFilter.filter(predicate);
filterResults.push(...filtered);
if(elementsWithChildren.length){
let childElements = [];
elementsWithChildren.forEach(x=>{
childElements.push(...x[childProperty]);
});
filterAndPushResults(childElements);
}
};
filterAndPushResults(this);
return filterResults;
}

Categories