Send Axios.get() Data to the HTML - javascript

I'm trying to make Axios.get() Send its Data to the HTML.
I'm Making To-Do app which as you guessed generates Todo list items on the page after entering value of the item in the input field(Also this items are being saved in the MongoDB)
I want to display every item from mongoDB in the style of Todo List items (With edit and delete button)
Any tips please?
let taskInput = document.getElementById("new-task");
let paginationBlock = document.getElementById("pagination");
let addButton = document.getElementsByTagName("button")[0];
addButton.setAttribute("id", "add");
let incompleteTaskHolder = document.getElementById("incomplete-tasks");
let paginationHolder = document.getElementById("pagination");
let listItem;
let label;
let editButton;
let deleteButton;
let editInput;
let checkBox;
let pageCount = 1;
let currentPage = 1;
let deleteCount = 0;
let storeData = [{}]
const setPageCount = () => {
const items = [...incompleteTaskHolder.children];
pageCount = Math.ceil(items.length / 5);
};
setPageCount();
const renderPagination = () => {
const items = [...incompleteTaskHolder.children]
paginationBlock.innerHTML = "";
for (let i = 1; i <= pageCount; i++) {
let pageBtn = document.createElement("button");
pageBtn.id = "pageBtn";
pageBtn.addEventListener("click", () => {
currentPage = i;
paginationDisplay();
});
pageBtn.innerText = i;
paginationBlock.append(pageBtn);
}
};
const paginationLimit = () => {
const items = [...incompleteTaskHolder.children];
if (items.length % 5 === 0) {
items.style.display = "none";
}
};
const paginationDisplay = () => {
const items = [...incompleteTaskHolder.children];
const start = (currentPage - 1) * 5;
const end = start + 5;
items.forEach((item, index) => {
if (index >= start && index < end) {
item.style.display = "block";
} else {
item.style.display = "none";
}
});
};
const sendData = () => {
let getValue = document.getElementById('new-task').value
axios.post('http://localhost:3000/add',{
todo : getValue
}).then(res => {
storeData.push({id : res.data._id})
console.log('res', res);
}).catch(err => {
console.log('err',err);
})
console.log(storeData)
}
const getAll = (data) => {
axios.get('http://localhost:3000').then(res => {
incompleteTaskHolder.innerHTML +=res.data
console.log('res',res.data);
}).catch(err => {
console.log('err',err);
})
}
getAll();
const deleteData = (id) => {
axios.delete(`http://localhost:3000/delete/${id}`,{
id : storeData
}).then(res => {
console.log('res',res)
}).catch(err => {
console.log('err',err)
})
};
let createNewTaskElement = function (taskString) {
listItem = document.createElement("li");
checkBox = document.createElement("input");
label = document.createElement("label");
editButton = document.createElement("button");
deleteButton = document.createElement("button");
editInput = document.createElement("input");
label.innerText = taskString;
checkBox.type = "checkbox";
editInput.type = "text";
editButton.innerText = "Edit";
editButton.className = "edit";
deleteButton.innerText = "Delete";
deleteButton.className = "delete";
listItem.appendChild(checkBox);
listItem.appendChild(label);
listItem.appendChild(editInput);
listItem.appendChild(editButton);
listItem.appendChild(deleteButton);
return listItem;
};
let addTask = function (showData) {
listItem = createNewTaskElement(taskInput.value);
document.getElementById("incomplete-tasks").appendChild(listItem);
bindTaskEvents(listItem, editButton);
setPageCount();
renderPagination();
paginationDisplay();
sendData();
};
let getInput = document.getElementById("new-task");
getInput.addEventListener("keyup", (event) => {
if (event.keyCode === 13) {
event.preventDefault();
document.getElementById("add").click();
}
});
let editTask = function () {
listItem = this.parentNode;
editInput = listItem.querySelector("input[type=text]");
label = listItem.querySelector("label");
containsClass = listItem.classList.contains("editMode");
if (containsClass) {
label.innerText = editInput.value;
} else {
editInput.value = label.innerText;
updateData();
}
listItem.classList.toggle("editMode");
};
let deleteTask = function () {
listItem = this.parentNode;
ul = listItem.parentNode;
ul.removeChild(listItem);
setPageCount();
renderPagination();
paginationDisplay();
deleteData();
};
addButton.onclick = addTask;
let bindTaskEvents = function (taskListItem) {
editButton = taskListItem.querySelector("button.edit");
deleteButton = taskListItem.querySelector("button.delete");
listItem = taskListItem.querySelector("label");
addButton = taskListItem.querySelector("button.add");
listItem.ondblclick = editTask;
editButton.onclick = editTask;
deleteButton.onclick = deleteTask;
};
for (let i = 0; i < incompleteTaskHolder.children.length; i++) {
bindTaskEvents(incompleteTaskHolder.children[i]);
}

Assuming you are getting a list of items as a response like ['todo1', 'todo2' 'todo3']. Let me know if your response is different in structure.
You can create a function that renders your todo list to HTML.
function createTodoList(todoArr) {
const container = document.createElement('div');
const todoList = document.createElement('ul');
document.getElementsByTagName('body')[0].appendChild(container);
container.appendChild(todoList);
todoArr.forEach(function(todo) {
const listItem = document.createElement('li');
listItem.textContent = todo;
todoList.appendChild(listItem);
});
}
// finally call the function with you response.data
createTodoList(res.data)
If you are getting a different response, you might have to

Related

Local storage in JS not loading items problem

I have a problem with the local storage it seems the items are getting saved to local storage but I cannot make it work to load at start.
Any tips and advice much appreciated.
I am posting the code below.
const input = document.getElementById('input');
const list = document.getElementById('list');
const addButton = document.getElementById('addButton');
const completed = document.getElementById("completed");
let LIST;
let id;
let loadSTORAGE = localStorage.getItem("STORAGE");
if (loadSTORAGE) {
LIST = JSON.parse(loadSTORAGE);
id = LIST.length;
loadList(LIST);
} else {
LIST = [];
id = 0;
}
function loadList() {
LIST.forEach(function() {
addTask();
});
}
addButton.addEventListener("click", addTask);
input.addEventListener("keyup", function(event) {
(event.keyCode === 13 ? addTask() : null)
})
function addTask() {
const newTask = document.createElement("li");
const delBtn = document.createElement("button");
const checkBtn = document.createElement("button");
delBtn.innerHTML = "<button>Reset</button>"
checkBtn.innerHTML = "<button>Done</button>"
if (input.value !== "") {
newTask.textContent = input.value;
list.appendChild(newTask);
newTask.appendChild(checkBtn);
newTask.appendChild(delBtn);
LIST.push({
name: input.value,
id: id,
});
id++
input.value = "";
console.log(LIST);
localStorage.setItem("STORAGE", JSON.stringify(LIST));
}
checkBtn.addEventListener("click", function() {
const parent = this.parentNode
parent.remove();
completed.appendChild(parent);
});
delBtn.addEventListener("click", function() {
const parent = this.parentNode
parent.remove();
});
}
You need to break out the logic of building the item and getting the value. Something like the following where the addTask just makes sure there is input and calls a method that builds an item. Now with the localstorage call, you can call just the code that builds the item.
const input = document.getElementById('input');
const list = document.getElementById('list');
const addButton = document.getElementById('addButton');
const completed = document.getElementById("completed");
const loadSTORAGE = localStorage.getItem("STORAGE");
const LIST = loadSTORAGE ? JSON.parse(loadSTORAGE) : [];
let id = LIST.length;
loadList(LIST);
function loadList() {
LIST.forEach(function(data) {
addTaskElement(data);
});
}
function addTask() {
if (input.value !== "") {
cons newItem = {
name: input.value,
id: id,
};
LIST.push(newItem);
id++;
localStorage.setItem("STORAGE", JSON.stringify(LIST));
input.value = "";
addTaskElement(newItem);
}
}
function addTaskElement(data) {
const newTask = document.createElement("li");
const delBtn = document.createElement("button");
const checkBtn = document.createElement("button");
delBtn.textContent = "Reset"
checkBtn.textContent = "Done"
newTask.textContent = data.name;
newTask.appendChild(checkBtn);
newTask.appendChild(delBtn);
list.appendChild(newTask);
}

Why I get duplicated todos in todo list?

This is the js code
let form = document.getElementById('todoForm');
let input = document.getElementById('todoInput');
let btn = document.getElementById('btn');
let todos = [];
const loadTodos = () => {
let parent = document.getElementById('todoList');
todos.forEach(todo => {
let newLi = document.createElement('li');
newLi.innerHTML = `<li>${todo.text}</li>`
parent.appendChild(newLi);
})
}
btn.addEventListener('click', (e) => {
e.preventDefault();
let text = input.value;
let todo = {
id: todos.length + 1,
text: text,
complete: false,
}
todos.push(todo);
loadTodos();
})
window.onload = () => {
loadTodos();
}
When I add a todo for the first time its ok, but the seconed time will print the first todo again include the seconed.
example:
first todo
2.first todo
3.seconed todo
You should make another function to handle single todo added, below is your updated code
let form = document.getElementById('todoForm');
let input = document.getElementById('todoInput');
let btn = document.getElementById('btn');
let todos = [];
const loadTodos = () => {
let parent = document.getElementById('todoList');
todos.forEach(todo => {
let newLi = document.createElement('li');
newLi.innerHTML = `<li>${todo.text}</li>`
parent.appendChild(newLi);
})
}
const renderNewToDo = (todo) => {
let parent = document.getElementById('todoList');
let newLi = document.createElement('li');
newLi.innerHTML = `<li>${todo.text}</li>`
parent.appendChild(newLi);
}
btn.addEventListener('click', (e) => {
e.preventDefault();
let text = input.value;
let todo = {
id: todos.length + 1,
text: text,
complete: false,
}
todos.push(todo);
renderNewToDo(todo);
})
window.onload = () => {
loadTodos();
}

Very new to Javascript OOP: Passing a value to property through input fails to render single Element

I'm having problems rendering individual "li" elements through OOP approach.
I'm fetching the input from the user and using this info to create an item through a class. I'm then connecting this class to the list class responsible for rendering the list.
Once I fetch the value through a click event listener, the singleTaskRendering class isn't working. I wonder if I'm setting this up incorrectly?
const inputAccess = document.querySelector('.control').querySelector('input');
const addItemBtnAccess = document.getElementById('add-item-btn');
const toDoList = [];
const doneList = [];
//ads a li id to the item
const idGenerator = (array) => {
let n = 1;
let message = '';
for (let i = 0; i < array.length; i++) {
n += 1;
}
message = `li-${n}`;
return message;
}
class ItemTask {
constructor(itemValue, idGen) {
this.title = itemValue;
this.id = idGen;
}
}
const addItemBtnHandler = () => {
const toDoList = [];
const inputValue = inputAccess.value;
const item= new ItemTask(inputValue, idGenerator(toDoList));
toDoList.push(item);
return toDoList;
};
class singleTaskRendering {
constructor(product) {
this.product = product;
}
render() {
const titleElement = document.createElement('div');
titleElement.id = this.product.id;
titleElement.innerHTML = `
<li>
<h2>${this.product.title}</h2>
<button>Done</button>
<button>Delete</button>
</li>`;
titleElement.draggable = true;
}
}
class ItemLists {
constructor(listId, items) {
this.items = items;
this.listId = listId;
console.log(this.items, this.listId);
}
renderList() {
const renderHook = document.getElementById('hook');
const createList = document.createElement('lu');
createList.className = 'card';
createList.id = `${this.listId}-list`;
for(let item of this.items) {
const newItem = new singleTaskRendering(item);
console.log(newItem);
const itemEl = newItem.render();
console.log(itemEl, newItem);
createList.apppend(itemEl);
}
renderHook.append(createList);
}
}
const itemList = new ItemLists('active', toDoList);
itemList.renderList();
addItemBtnAccess.addEventListener('click', addItemBtnHandler);
The problem that you are having is that you call ItemLists on page load, which means it will only be processing an empty toDoList.
My solution is to rename renderList to appendItem.
Declare it at the top
Don't pass the list id and list to the constructor instead pass it to
appendItem in the clickhandler.
const inputAccess = document.querySelector('.control').querySelector('input');
const addItemBtnAccess = document.getElementById('add-item-btn');
const itemList = new ItemLists();
const toDoList = [];
const doneList = [];
//ads a li id to the item
const idGenerator = (array) => {
let n = 1;
let message = '';
for (let i = 0; i < array.length; i++) {
n += 1;
}
message = `li-${n}`;
return message;
}
class ItemTask {
constructor(itemValue, idGen) {
this.title = itemValue;
this.id = idGen;
}
}
const addItemBtnHandler = () => {
const toDoList = [];
const inputValue = inputAccess.value;
const item= new ItemTask(inputValue, idGenerator(toDoList));
itemList.appendItem('active', item);
};
class singleTaskRendering {
constructor(product) {
this.product = product;
}
render() {
const titleElement = document.createElement('div');
titleElement.id = this.product.id;
titleElement.innerHTML = `
<li>
<h2>${this.product.title}</h2>
<button>Done</button>
<button>Delete</button>
</li>`;
titleElement.draggable = true;
}
}
class ItemLists {
appendItem(listId, item) {
const renderHook = document.getElementById('hook');
const createList = document.createElement('lu');
createList.className = 'card';
createList.id = `${listId}-list`;
const newItem = new singleTaskRendering(item);
console.log(newItem);
const itemEl = newItem.render();
console.log(itemEl, newItem);
createList.apppend(itemEl);
renderHook.append(createList);
}
}
addItemBtnAccess.addEventListener('click', addItemBtnHandler);

how to loop through each list and add local stored item in it

I have a Bookmark Page where I add edit and delete bookmarks. and I have stored these items in localStorage. the issue is in loaddata function where I get the stored data and save it back in newly created li. the li tag is storing all the inputs that I typed in just one list. what I want is each bookmark should be within its own list just like additem function. but I don't know how to achieve this
const search = document.querySelector('form input');
const input = document.querySelector('.add-text');
const container = document.querySelector('ul');
let items = null;
let currentItem = null;
let array = [];
const searchItems = function(e) {
if (items) {
let word = e.target.value.toLowerCase();
for (let item of items) {
if (item.firstChild.textContent.toLowerCase().indexOf(word) !== -1) {
item.style.display = 'block';
} else {
item.style.display = 'none';
}
}
}
}
const deleteItem = function(e) {
currentItem = null;
e.target.parentNode.remove();
input.value = '';
}
const editItem = function(e) {
currentItem = e.target.parentNode.firstChild;
input.value = currentItem.textContent;
}
const updateItem = function(e) {
if (currentItem) {
currentItem.textContent = input.value;
input.value = '';
}else{
alert('No Selected Text Here to Update');
return;
}
}
const addItem = function() {
let val = input.value;
if (val) {
let li = document.createElement('li');
let inner = '<h1 class="text">' + val + '</h1>';
inner += '<button class="delete">Delete</button>';
inner += '<button class="edit">Edit</button>';
array.push(inner);
let stringified = JSON.stringify(array);
localStorage.setItem('list', stringified);
li.innerHTML = inner;
container.appendChild(li);
input.value = '';
currentItem = li.firstChild;
items = document.querySelectorAll('li');
for (let del of document.querySelectorAll('.delete')) {
del.addEventListener('click', deleteItem);
}
for (let edit of document.querySelectorAll('.edit')) {
edit.addEventListener('click', editItem);
}
} else {
alert('please add some text');
return;
}
}
function loaddata(){
let li = document.createElement('li');
let stringified = localStorage.getItem('list');
let listitems = JSON.parse(stringified);
li.innerHTML = listitems;
container.appendChild(li);
console.log(li);
}
loaddata();
search.addEventListener('keyup', searchItems);
document.querySelector('#add').addEventListener('click', addItem);
document.querySelector('#update').addEventListener('click', updateItem);
Considering your list is an array, you need to loop through it and create adn populate elements within that loop. Try to edit your loaddata function this way:
// Mock content
let container = document.body
localStorage.setItem('list', JSON.stringify(['<h1>Foo</h1>', '<h1>Bar</h1>', '<h1>Baz</h1>']))
loaddata()
// Edited 'loaddata'
function loaddata() {
let stringified = localStorage.getItem('list');
console.log(stringified)
let listitems = JSON.parse(stringified);
for (let i = 0; i < listitems.length; i++) {
let li = document.createElement('li');
li.innerHTML = listitems[i];
container.appendChild(li);
console.log(li);
}
}
It can't be run like a code snippet in Stack Overflow sandbox due to security reasons (accessing Local Storage), so if you want to test it, consider copying to JSFiddle or so.

How to remove a class from grandfather div

I have a code like this. It is here only to show how It works. Problem appears when I want to compare cards. When I click on the first and second card and they are not matched their grandfather div should remove a class which flips a tile. Second thing, I click on the same card twice it will return "win". How to fix this and make this code look clean?
{
let guesses = [];
let tries = 0;
const doubleArrVal = arr => arr.concat(arr);
const addFlipEffect = (e) => {
let target = e.currentTarget;
if (!target.classList.contains("tile--static")) {
target.classList.add("tile--active");
}
return target;
};
const addManyListeners = (collection, e, fn) => {
for (let i = 0; i < collection.length; i++) {
collection[i].addEventListener(e, fn, false);
}
};
const randomize = (arr) => {
for (let i = 0; i < arr.length; i++) {
const j = Math.floor(Math.random() * (i + 1));
const tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
return arr;
};
const prepareArray = (ammount) => {
let imgNames = ["angular", "bootstrap", "css", "foundation", "github", "grunt", "html", "ruby", "jquery", "less", "nodejs", "sass"];
imgNames = imgNames.slice(0, ammount);
const doubled = doubleArrVal(imgNames);
return randomize(doubled);
};
const createMarkUp = (id) => {
const markUp = `<div class="tile tile--game">
<div class="tile__side tile__side--front">
</div>
<div class="tile__side tile__side--back">
<img src="img/${id}.svg" alt="${id}" class="tile__img" data-name="${id}">
</div>
</div>`;
return markUp;
};
const createCards = (ammount) => {
const container = document.getElementById("gameContainer");
const preparedCards = prepareArray(ammount);
preparedCards.map(card => {
const cardElement = createMarkUp(card);
container.innerHTML += cardElement;
});
return container;
};
// Problem is here
const compare = (e) => {
const userPick = e.currentTarget;
let image = userPick.querySelector("[data-name]");
guesses.push(image);
tries++;
if (tries === 2) {
if (guesses[0].dataset.name === guesses[1].dataset.name) {
console.log("win");
} else {
setTimeout(() => {
guesses[0].parentNode.parentNode.classList.remove("tile--active");
guesses[1].parentNode.parentNode.classList.remove("tile--active");
}, 500);
}
guesses = [];
tries = 0;
}
}
const startGame = (level) => {
const gameCards = createCards(4);
addManyListeners(gameCards.children, "click", addFlipEffect);
addManyListeners(gameCards.children, "click", compare);
};
startGame();
}
<div id ="gameContainer"></div>
I would use a Set for guesses, to facilitate the unique selection:
let guesses = new Set;
//...
const compare = (e) => {
const userPick = e.currentTarget;
let image = userPick.querySelector("[data-name]");
guesses.add(image);
if (guesses.size === 2) { // guaranteed to be 2 different images
if (new Set(Array.from(guesses, guess => guess.dataset.name)).size == 1) {
console.log("win");
guesses = new Set;
} else {
setTimeout(() => {
for (let guess of guesses) {
guess.parentNode.parentNode.classList.remove("tile--active");
}
guesses = new Set; // only clear here
}, 500);
}
}
}
If your template would put the data-name="${id}" on the grandfather/root div, it would all become a bit simpler: then you only have to work with the div, not the img:
const createMarkUp = (id) => {
const markUp = `<div class="tile tile--game" data-name="${id}">
<div class="tile__side tile__side--front">
</div>
<div class="tile__side tile__side--back">
<img src="img/${id}.svg" alt="${id}" class="tile__img">
</div>
</div>`;
return markUp;
};
//...
const compare = (e) => {
guesses.add(e.currentTarget);
if (guesses.size !== 2) return;
if (new Set(Array.from(guesses, guess => guess.dataset.name)).size == 1) {
console.log("win");
guesses = new Set;
return;
}
setTimeout(() => {
for (let guess of guesses) {
guess.classList.remove("tile--active");
}
guesses = new Set;
}, 500);
}
This is an error of scope. Your timeout uses the variable guesses but it is executed in the global scope, where the variable is undefined. So I have used bind, to bind it to the function.
To make sure you have 2 different elements in guesses, simply test them before testing their value.
{
let guesses = [];
let tries = 0;
const doubleArrVal = arr => arr.concat(arr);
const addFlipEffect = (e) => {
let target = e.currentTarget;
if (!target.classList.contains("tile--static")) {
target.classList.add("tile--active");
}
return target;
};
const addManyListeners = (collection, e, fn) => {
for (let i = 0; i < collection.length; i++) {
collection[i].addEventListener(e, fn, false);
}
};
const randomize = (arr) => {
for (let i = 0; i < arr.length; i++) {
const j = Math.floor(Math.random() * (i + 1));
const tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
return arr;
};
const prepareArray = (ammount) => {
let imgNames = ["angular", "bootstrap", "css", "foundation", "github", "grunt", "html", "ruby", "jquery", "less", "nodejs", "sass"];
imgNames = imgNames.slice(0, ammount);
const doubled = doubleArrVal(imgNames);
return randomize(doubled);
};
const createMarkUp = (id) => {
const markUp = `<div class="tile tile--game">
<div class="tile__side tile__side--front">
</div>
<div class="tile__side tile__side--back">
<img src="img/${id}.svg" alt="${id}" class="tile__img" data-name="${id}">
</div>
</div>`;
return markUp;
};
const createCards = (ammount) => {
const container = document.getElementById("gameContainer");
const preparedCards = prepareArray(ammount);
preparedCards.map(card => {
const cardElement = createMarkUp(card);
container.innerHTML += cardElement;
});
return container;
};
const compare = (e) => {
const userPick = e.currentTarget;
let image = userPick.querySelector("[data-name]");
guesses.push(image);
tries++;
if (tries === 2) {
if (guesses[0] !== guesses[1] && guesses[0].dataset.name === guesses[1].dataset.name) {
console.log("win");
} else {
setTimeout(((guesses) => {
guesses[0].parentNode.parentNode.classList.remove("tile--active");
guesses[1].parentNode.parentNode.classList.remove("tile--active");
}).bind(null, guesses), 500);
}
guesses = [];
tries = 0;
}
}
const startGame = (level) => {
const gameCards = createCards(4);
addManyListeners(gameCards.children, "click", addFlipEffect);
addManyListeners(gameCards.children, "click", compare);
};
startGame();
}
<div id="gameContainer"></div>

Categories

Resources