Create Html Tree view with native javascript / HTML - javascript

I need to create an HTML/CSS tree view as in the example from already created object using native javascript.
Please suggest,
BR

You could first build nested structure and then use recursive approach to also create html from that data where if the current element has children property you call the function again with that children array as a data parameter.
var data = [{"name":"container-1","type":"container","description":"container description"},{"name":"category-1","type":"category","parent":"container-1"},{"name":"grid-1","type":"grid","parent":"category-1"},{"name":"chart-1","type":"chart","parent":"category-1"},{"name":"container-2","type":"container"},{"name":"category-2","type":"category","parent":"container-2"},{"name":"category-3","type":"category","parent":"container-2"},{"name":"grid-2","type":"grid","parent":"category-2"},{"name":"chart-2","type":"chart","parent":"category-2"},{"name":"grid-3","type":"grid","parent":"category-3"}]
function toTree(data, pid = undefined) {
return data.reduce((r, e) => {
if (pid == e.parent) {
const obj = { ...e }
const children = toTree(data, e.name)
if (children.length) obj.children = children;
r.push(obj)
}
return r
}, [])
}
function toHtml(data, isRoot = true) {
const ul = document.createElement('ul')
if (!isRoot) {
ul.classList.add('hide')
}
data.forEach(e => {
let isVisible = isRoot;
const li = document.createElement('li')
const text = document.createElement('span')
const button = document.createElement('button')
if (e.children) {
button.textContent = '+'
li.appendChild(button)
}
text.textContent = e.name
li.appendChild(text)
if (e.children) {
const children = toHtml(e.children, false)
li.appendChild(children)
button.addEventListener('click', function() {
if (isRoot) {
isVisible = !isVisible
}
button.textContent = isVisible ? '+' : '-'
children.classList.toggle('hide')
if (!isRoot) {
isVisible = !isVisible
}
})
}
ul.appendChild(li)
})
return ul;
}
const tree = toTree(data)
const html = toHtml(tree)
document.body.appendChild(html)
.hide {
display: none;
}
button {
margin-right: 10px;
}

Related

Why isn't my classlist removing when using this constructor function

So i'm trying to remove my classlist of selected items when they are clicked again:
const todo = []
const elements = []
const todoList = document.getElementById('todoList')
const addItem = document.getElementById('textBox')
const submit = document.getElementById('submit')
const todoListItem = document.querySelectorAll('.todoListItem')
const todoListItemArr = Array.from(todoListItem)
const deleteItem = document.getElementById('deleteButton')
let selected
class Div {
constructor(content) {
this.content = content
}
addToScreen(){
const element = document.createElement('div')
element.innerHTML = this.content
element.classList.add('todoListItem')
todoList.appendChild(element)
}
select(){
const element = document.querySelectorAll('.todoListItem')
element.forEach(item => {
item.addEventListener('click', () => {
item.classList.add('selectedItem')
selected = item
})
})
}
deselect() {
const elements = document.querySelectorAll('.selectedItem')
elements.forEach(item => {
item.addEventListener('click', () => {
item.classList.remove('selectedItem')
})
})
}
}
function createItem() {
const todoItem = new Div(addItem.value)
todoItem.addToScreen()
todo.push(todoItem.content)
console.log(todo)
addItem.value = ''
todoItem.select()
todoItem.deselect()
}
addItem.addEventListener('keypress', (e) => {
if(e.key == 'Enter') {
createItem()
}
})
submit.addEventListener('click', createItem)
also I'm trying to add a delete function, but everytime i try to remove the element in the constructor by adding a delete function, my delete button does nothing, i've removed those features for now.

How can i add Local Storage to my todolist?

I am doing some practice javascript exercise. My project look like 'trello' but much soft and simple.
When i writing some notes to input, javscript adding note dynamically but if i refresh the page/chrome, all things gone or lost.
So i wanna apply localstorage on my project. How can i do it.
My Note project: https://codepen.io/daniel_134/pen/NWwYKyK[My Note project]1
var input = document.querySelector('#text-input');
document.querySelector("#ad-note-btn").addEventListener("click", () => {
if (input.value.length > 1) {
// GET-INPUT-VALUE
var getvalue = input.value;
// CREATE-NEW-NOTE
const newLi = document.createElement("textarea");
newLi.value = getvalue;
newLi.className = "note-li";
// ADD-NEW-NOTE
var ul = document.querySelector('#list-items');
ul.appendChild(newLi);
// EMPTY-INPUT-WHEN-CREATING-NEW-NOTES
input.value = " ";
// DELETE-NOTES
const dleLi = document.createElement("button");
dleLi.textContent = "delete";
dleLi.className = "list-btn";
ul.appendChild(dleLi);
dleLi.addEventListener("click", () => {
newLi.remove();
dleLi.remove();
edLi.remove();
saveLi.remove();
})
// EDIT-NOTES
const edit = () => {
if( newLi.value.length > 0 ) {
newLi.disabled = true;
} else {
newLi.disabled = false;
}
}
edit()
const edLi = document.createElement("button");
edLi.textContent = "Edit";
ul.appendChild(edLi);
edLi.className = "list-btn";
edLi.addEventListener("click", () => {
if ( newLi.disabled = true ) {
newLi.disabled = false;
}else {
newLi.disabled = true;
}
})
const saveLi = document.createElement("button");
saveLi.textContent = "save";
ul.appendChild(saveLi);
saveLi.className = "list-btn";
saveLi.addEventListener("click", () => {
edit();
})
} else {
ul.appendChild();
}
})
document.querySelector("#clear-btn").addEventListener("click", () => {
input.value = " ";
})
2
it'll look like that , for example :
when you load your page .
load todoList var todoList = JSON.parse(localStorage.getItem('todo-list'))
and display it
when you add new element to your to-do list
var todoList = JSON.parse(localStorage.getItem('todo-list'));
var new_todo = [{
title:'for example ...',
complete:false
}];
localStorage.setItem('todo-list',JSON.stringify(new_todo));
}else{
todoList.push({
title:'for example ...',
complete:false
});
localStorage.setItem('todo-list',JSON.stringify(todoList));
}

how to add a element with href on li element?

i have a search system on my website it works but i can not click on items i search. its a simple script that creates li elements dephended on my search input but how can i add this elements a custom links? because if you can not click on item you searched that does not make any sense... i want to add this const people elements custom links.code:
const people = [
{name:'გადაარჩინე დედამიწა'},
{name:'ანტიმელა'},
{name:'mr.capsule'},
{name:'capsule battle royale'}
];
const list = document.getElementById('list');
function setlist (group) {
clearlist();
for (const person of group) {
const item = document.createElement("li");
item.classList.add("list-group-item");
const text = document.createTextNode(person.name);
item.appendChild(text);
list.appendChild(item);
}
if (group.length === 0) {
setnoresults();
}
}
function clearlist () {
while (list.firstChild) {
list.removeChild(list.firstChild);
}
}
function getrelevency (value, searchTerm) {
if (value === searchTerm) {
return 2;
}else if (value.startsWith(searchTerm)) {
return 1;
}else if (value.includes(searchTerm)) {
return 0;
}
}
function setnoresults () {
const item = document.createElement('li');
item.classList.add('list-group-item');
const text = document.createTextNode('შედეგები ვერ მოიძებნა... სცადეთ თავიდან');
item.appendChild(text);
list.appendChild(item);
}
const searchInput = document.getElementById('search');
searchInput.addEventListener('input', (event) => {
let value = event.target.value;
if (value && value.trim().length > 0) {
value = value.trim().toLowerCase();
setlist(people.filter(person => {
return person.name.includes(value);
}).sort((personA, personB) => {
return getrelevency(personB.name, value) - getrelevency(personA.name, value);
}));
}else {
clearlist();
}
});
You should add it in setlist function.
function setlist (group) {
clearlist();
for (const person of group) {
const item = document.createElement("li");
item.classList.add("list-group-item");
const link = document.createElement("a");
link.href = "http://..."; // put here where the link should point
item.appendChild(link);
const text = document.createTextNode(person.name);
link.appendChild(text);
list.appendChild(item);
}
if (group.length === 0) {
setnoresults();
}
}
i got solution with this way checking what search input is and if its targeted search it will add a link on custom search. if statemant is doing everything!
function setlist (group) {
clearlist();
for (const person of group) {
const item = document.createElement("li");
item.classList.add("list-group-item");
if (person.name === "გადაარჩინე დედამიწა") {
const link = document.createElement("a");
link.href = "https://google.com"; // put here where the link should point
link.text = "გადაარჩინე დედამიწა"
item.appendChild(link);
}
const text = document.createTextNode(person.name);
item.appendChild(text);
list.appendChild(item);
}
if (group.length === 0) {
setnoresults();
}
}

Select list filter json data

I want to do filtering from json by select list. now when I choose value from the select list, it gives selected products at the end of the list, and I want to show only those selected
function showContent(data) {
const contentBox = document.querySelector('#content__products');
const select = document.querySelector('.products__select');
data.map(function (product) {
return selectCat(product)
})
}
function selectCat(product) {
const select = document.querySelector('.products__select');
createProduct(product)
select.addEventListener('change',() => {
if(select.value == product.cat) {
createProduct(product);
}
})
}
function createProduct(product) {
const contentBox = document.querySelector('#product__list');
const element = prepareElement('div',['product__elem']);
const imageElement = prepareElement('img', ['product__img'], element);
const nameProd = prepareElement('p',['product__name'], element);
const catProd = prepareElement('p',['product__cat'], element);
contentBox.appendChild(element)
imageElement.setAttribute('src', product.img);
nameProd.innerText = product.name;
catProd.innerText = 'Category:' + ' ' + product.cat;
}
You can hide elements that don't match to your filter. In your code, I assume that you need to clean the container with products first.
function selectCat(product) {
const select = document.querySelector('.products__select');
createProduct(product)
select.addEventListener('change',() => {
var contentBox = document.getElementById('product__list');
while (contentBox.firstChild) {
contentBox.removeChild(contentBox.firstChild);
}
if(select.value == product.cat) {
createProduct(product);
}
})
}

generate elements based on key structure of object

I have an multidimensional object. Now I wanna generate DOM-elements based on the key structure of this object.
As a default view all root keys should be shown as div elements. With a click on one of this elements the divs should be replaced with the direct children of the clicked key.
My current version looks like this
object:
let object = {
"1.0": {
"1.0.1": {},
"1.0.2": {},
},
"1.1": {
"1.1.1": {
"1.1.1.1": {},
},
"1.1.2": {},
},
};
this is my recursive function to generate DOM elements for each key:
function categoryTree(obj) {
for (var key in obj) {
categoryContainer.innerHTML += "<div>" + key + "</div>";
categoryTree(obj[key]);
}
}
Now, I don't know how to make this interactive and show the child keys only when the parent was clicked.
You could build nested html structure with createElement and for...in loop. And then you can also add event listener on div that will toggle its children display property.
let object = {
"1.0": {
"1.0.1": {},
"1.0.2": {}
},
"1.1": {
"1.1.1": {
"1.1.1.1": {}
},
"1.1.2": {}
}
}
let categoryContainer = document.querySelector(".categoryContainer")
function categoryTree(obj, parent, start = true) {
for (var key in obj) {
let div = document.createElement("div");
div.textContent = key;
if (parent.children) parent.className += " bold";
if (!start) div.className = "normal hide"
div.addEventListener('click', function(e) {
e.stopPropagation()
Array.from(div.children).forEach(child => {
child.classList.toggle('hide')
})
})
categoryTree(obj[key], div, false)
parent.appendChild(div)
}
}
categoryTree(object, categoryContainer)
.hide {display: none;}
.normal {font-weight: normal;}
.bold {font-weight: bold;}
<div class="categoryContainer"></div>
Just use the DOM methods:
const n = (type, settings = {}) => Object.assign(document.createElement(type), settings);
function treeNode(name, children) {
const text = n("p", { textContent: name });
const container = n("div");
container.style.display = "none";
for(const [childName, child] of Object.entries(children))
container.appendChild(treeNode(childName, child));
const node = n("div");
node.appendChild(text);
node.appendChild(container);
node.onclick = () => container.style.display = "block";
return node;
}
categoryContainer.appendChild(treeNode("root", object));

Categories