How can I add CSS to retrieved local storage items? - javascript

I have an online diary application. Everytime a user enters a block of text, it gets saved as an entry below. I can successfully add those entries into local storage and access it to display it when the screen is refreshed, but I want to add CSS to those retrieved items, to make them look the same as when they are first added to the list. I've tried multiple approaches, but nothing seems to work.
//Online journal functionality
function _(id) {
return document.getElementById(id)
}
function getRs() {
let text = _('text').value
const d = new Date()
_('rs').innerHTML += `<div class="card"><p>${text}</p>
<small>${d.toLocaleTimeString()}, ${d.toLocaleDateString()}</small></div>`
}
//Local storage
const input = document.querySelector('.text');
const entry = document.querySelector('.entry')
const saveButton = document.querySelector('.save-btn');
const clearButton = document.querySelector('.clear-btn');
const storedInput = localStorage.getItem('textinput');
if (input) {
entry.textContent = storedInput
}
const saveToLocalStorage = () => {
localStorage.setItem('textinput', entry.textContent)
};
function clearStorage() {
localStorage.clear();
};
saveButton.addEventListener('click', saveToLocalStorage);
clearButton.addEventListener('click', clearStorage);
<header class="diary-title">
<h2>My online diary</h2>
</header>
<div class="wrapper" style="margin-left: 440px;">
<textarea class="text" id="text" rows="3" placeholder="How are you feeling today?" style="width: 600px; height: 150px; text-align: center;"></textarea>
</div>
<div class="diary-btn" id="diary-btn">
<button onclick="getRs()" style="background-color: #55725d; color: #e8e6ea; padding: 5px; text-align: center; border-color: transparent; margin-left: 690px; margin-top: 7px;">Create entry</button>
</div>
<div class="localstore">
<button class="save-btn" id="save-btn">Save</button>
<button class="clear-btn" id="clear-btn">Clear</button>
</div>
<div id="rs" class="entry" style="max-width: 1000px; align-content: center; margin-left: 180px;"></div>
I want to add this CSS to the retrieved items displayed (so the storedInput variable):
padding: 0.5rem 1rem;
border: 1px solid #55725d;
padding-bottom: 5px;
border-radius: 3px;
margin: 0.5rem 0;

Just store your css in a class and after retrieving the items from localStroge.
use
document.getElementById("myDIV").element.classList.add("classname");
Make sure you have linked your css correctly in your html file.

Related

One event handler function not getting triggered after the execution of another event handler function defined in the same js file

I am trying to build a static todo app, this app stores the todo list in localStorage (browser memory).
there are 3 elements related to the error - 1 element is causing the error and the other 2 being affected by it.
a hide complete checkbox - hides the completed tasks when checked. (element causing the error)
complete todo checkbox - mark a todo as completed when checked.
delete note button - deletes a note.
I have attached the code files and screenshot, to get an overall idea about the problem and the code.
along with this, I have stored my code in this repo: https://github.com/AbhishekTomr/Todo
Problem - Once the hide completed checkbox is triggered, the complete todo and delete todo mechanism stops working.
Can someone please help me in fixing the code or let me know what is causing the issue?
Screenshot:
//js file : todoFunctions.js
//function for getting value stored in todoList
let getTodo = function(){
return Boolean(localStorage.getItem("todo"))?JSON.parse(localStorage.getItem("todo")):[];
}
//function to add or render any list on the screen
let render = function(list){
document.querySelector("#td").innerHTML = "";
list.forEach(function(item){
newTask(item);
}
)
}
//function for saving the task in the local storage
let saveTask = function(todo){
let tdList = JSON.stringify(todo);
localStorage.setItem("todo",tdList); //setting value for the first time or updating it
}
let newTask = function(node)
{
let li = document.createElement("li");
let status = document.createElement("input");
let remove = document.createElement("button");
li.textContent = node.td;
remove.setAttribute("class","remove");
remove.textContent="Delete";
status.setAttribute("type","checkbox");
status.setAttribute("class","status");
status.checked = node.status;
li.style.textDecoration = (node.status)?"line-through":"none";
let div = document.createElement("div");
div.setAttribute("class","task");
div.setAttribute("id",node.index);
div.appendChild(status);
div.appendChild(li);
div.appendChild(remove);
document.querySelector("#td").appendChild(div);
document.getElementById("new-task").value = ""; //clearing the input feild
}
//function for adding a new task
let addTask = function(todo){
let td = document.getElementById("new-task").value;
let status = false;
let node = {td : td,status : status};
todo.push(node);
saveTask(todo); // saving it to local storage
newTask(node);
}
// function for searching out task
let searchTask = function(todo,e){
let searchList = todo.filter(function(item){
return item.td.includes(e.target.value);
})
render(searchList); // showing the searched terms on the go..
}
//funtion to delete task
let deleteTodo=function(e,index,todo){
e.target.parentElement.remove();
todo.splice(index,1);
saveTask(todo);
}
//funtion for completing and undoing a task
let changeStatus = function(e,index,todo){
let state = e.target.checked;
let td = e.target.parentElement.children[1];
td.style.textDecoration = (state)?"line-through":"none";
todo[index].status = state;
saveTask(todo);
}
//function for hiding complete task
let hideCompleted = function(e,todo){
if(e.target.checked)
{
let filterLst = todo.filter(function(item){
return !item.status;
})
render(filterLst);
}else{
render(todo);
}
}
//js file :main.js
let todo = getTodo(); // get the todo List from storage
render(todo); // display the initial todo List
//functionality for the different events
document.getElementById("add-task").addEventListener("click",function(e){ //event when the add new task button is pressed
addTask(todo); //funtion for adding new task and displaying it on page
})
document.getElementById("search-txt").addEventListener("input",function(e){ //event for text typed in seach bar
searchTask(todo,e); //funtion for searching the tasks and displaying it on page
})
//event to delete todo
let btns = document.querySelectorAll(".remove");
btns.forEach(function(item,index){
item.addEventListener("click",function(e){
deleteTodo(e,index,todo);
})
})
//event for complete/uncomplete task
let check = document.querySelectorAll(".status");
check.forEach(function(item,index){
item.addEventListener("change",function(e){
changeStatus(e,index,todo);
console.log("i am triggered");
})
})
document.querySelector("#hide-check").addEventListener("change",function(e){ //event when hide completed is checked and unchecked
hideCompleted(e,todo);
})
/* css file : main.css */
*{
margin: 0;
padding: 0;
box-sizing: border-box;
/* border: 1px solid black; */
font-family: monospace;
}
main{
margin: 5px;
}
h1{
font-size: 3rem;
font-weight: bold;
font-variant: small-caps;
display: inline-block;
width: 250px;
text-align: center;
}
#td-options{
display: flex;
flex-flow: column nowrap;
justify-content:space-around;
align-items: flex-start;
font-size: 1.2rem;
width: 250px;
}
#search,#search input{
width: 100%;
height: 100%;
text-align: center;
border: 2px solid black;
}
#hide-completed{
width: 100%;
display: flex;
justify-content: flex-start;
align-items: center;
font-size: 1.2rem;
margin: 5px 0;
}
#hide-check{
margin: 10px;
}
#todo{
/* border: 3px solid pink; */
background-color: pink;
margin: 1rem 0;
display: inline-block;
padding: 10px;
}
.task{
border: 1px solid green;
display: flex;
justify-content: flex-start;
align-items: center;
font-size: 1.2rem;
}
.task li{
list-style-position: inside;
margin: .5rem;
text-transform: capitalize;
}
.task button{
padding: 0 .5rem;
border-radius: 2px;
background-color: gray;
color: whitesmoke;
}
.task button:hover{
cursor: pointer;
}
#add-todo{
display: flex;
flex-flow: row nowrap;
width: 255px;
justify-content: space-between;
height: 25px;
}
#add-todo button{
padding: 0 .5rem;
border-radius: 3px;
}
<!-- html file: index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="main.css">
<title>Todo</title>
</head>
<body>
<main>
<!-- mainheading -->
<h1>My Todo App</h1>
<!--todoOptions-->
<div id="td-options">
<div id="search">
<input type="text" id="search-txt" placeholder="search your Todo">
</div>
<div id="hide-completed">
<label for="hide-check">
Hide Completed Tasks
</label>
<input type="checkbox" id="hide-check" name="hide">
</div>
</div>
<!-- todo list -->
<div id="todo">
<ol id="td"></ol>
</div>
<!-- add todo -->
<div id="add-todo">
<input type="text" placeholder="Add A New To Do Task" id="new-task">
<button id="add-task">Add ToDo</button>
</div>
<!-- js files -->
<script src="todoFunctions.js"></script>
<script src="main.js"></script>
</main>
</body>
</html>
The function render goes through a list and creates the relevant elements for a task to show it on the screen and then appends them.
At the start a list is collected from localstorage and then all the required event listeners are added.
When hideCompleted is called it creates a list from the remaining elements that are not completed, or just uses the complete todo list, and re-renders it. This creates all the elements OK so everything looks alright on the screen.
BUT no event listeners are added so the delete button and so on do not do anything.
My suggestion would be to make the event listener creation code for .remove etc into a function. Call that on start up and when you recreate the list on screen.

Converting string to DOM node (ul/li) in JavaScript with appendchild

I am trying to make use of createElement, createTextNode and appendChild to rewrite an outdated simple to-do list code example.
The code example requires the use of the array join() method so, unfortunately, this can't be removed. The old version just wrote the HTML for the ul list in code fragments.
I am unsure how to proceed where I have entered to comment at line 30 of the js: " need to render the tasks (from stringToInsert) as a list to div id="output" here "
I have referred to the following stackoverflow articles to help me rewrite the code:
js-how-to-concatenate-variables-inside-appendchild -This example uses join() and appendChild but not list items.
create-ul-and-li-elements-in-javascript-
From that one, I copied the code from a Fiddle and put it into function createul() in my example codepen
Once I have the function addTask() working createul() and it's associated HTML elements (such as the render list button) will be removed.
// tasks.js #2
// This script manages a to-do list.
// Need a global variable:
var tasks = [];
function addTask() {
'use strict';
console.log("addTask started");
// Get the task:
var task = document.getElementById('task');
// Reference to where the output goes:
var output = document.getElementById('output');
if (task.value) {
tasks.push(task.value);
// Update the page:
//var message = '<h2>To-Do</h2>';
var stringToInsert = tasks.join(' : ');
console.log(stringToInsert);
var taskUl = document.createElement('ul');
taskUl.setAttribute('id', 'autoTask');
document.getElementById('output').appendChild(taskUl);
/* need to render the tasks (from stringToInsert) as a list to div id ="output" here */
document.getElementById("task").value = '';
}
// Return false to prevent submission:
return false;
} // End of addTask() function.
function createul() {
var ul = document.createElement('ul');
ul.setAttribute('id', 'proList');
var t, tt;
productList = ['Electronics Watch', 'House wear Items', 'Kids wear', 'Women Fashion'];
document.getElementById('renderList').appendChild(ul);
productList.forEach(renderProductList);
function renderProductList(element, index, arr) {
var li = document.createElement('li');
li.setAttribute('class', 'item');
ul.appendChild(li);
t = document.createTextNode(element);
li.innerHTML = li.innerHTML + element;
}
}
function init() {
document.getElementById('renderbtn').addEventListener("click", createul);
document.getElementById('theForm').onsubmit = addTask;
}
window.addEventListener('load', init);
/* css (I have simplified this a little for this example and I am sorry I haven't cut it down further) */
form {
margin: 0 auto;
width: 400px;
padding: 14px;
background-color: #ffffff;
border: solid 2px #425955;
}
/* ----------- stylized ----------- */
h1 {
font-size: 14px;
font-weight: bold;
margin-bottom: 8px;
}
p {
font-size: 11px;
color: #666666;
margin-bottom: 20px;
border-bottom: solid 1px #BFBD9F;
padding-bottom: 10px;
}
label {
display: block;
font-weight: bold;
text-align: right;
width: 140px;
float: left;
}
select {
float: left;
font-size: 12px;
padding: 4px 2px;
border: solid 1px #BFBD9F;
width: 200px;
margin: 2px 0 20px 10px;
}
input {
float: left;
font-size: 12px;
padding: 4px 2px;
border: solid 1px #BFBD9F;
width: 200px;
margin: 2px 0 20px 10px;
}
#submit {
clear: both;
margin-left: 150px;
width: 125px;
height: 31px;
background: #F1F2D8;
text-align: center;
line-height: 20px;
color: #000000;
font-size: 12px;
font-weight: bold;
}
#output {
clear: both;
margin-bottom: 10px;
color: blue;
}
<form action="#" method="post" id="theForm">
<div><label for="task">Task</label><input type="text" name="task" id="task" required></div>
<input type="submit" value="Add It!" id="submit"><br>
<button type="button" id="renderbtn">render list</button>
<div id="renderList"></div>
<div id="output"></div>
edit: I can just convert it back to an array with something like the following if there is no other way of doing it.
var ar = stringToInsert.split(' : ');
or something based on:
stringToInsert.split(' : ').forEach ... or if that doesn't work I could try map()
I'm going to show you a different approach that may help clear things up -
function ul (nodes)
{ const e = document.createElement("ul")
for (const n of nodes)
e.appendChild(n)
return e
}
function li (text)
{ const e = document.createElement("li")
e.textContent = text
return e
}
function onSubmit (event)
{ event.preventDefault()
tasks.push(f.taskInput.value)
f.taskInput.value = ""
render()
}
function render ()
{ const newList = ul(tasks.map(li))
f.firstChild.replaceWith(newList)
}
const tasks = [ "wash dishes", "sweep floors" ] // <- initial tasks
const f = document.forms.main // <- html form
f.addButton.addEventListener("click", onSubmit) // <- button listener
render() // <- first render
<h3>todo list</h3>
<form id="main">
<ul></ul>
<input name="taskInput" placeholder="example: paint fence">
<button name="addButton">Add Task</button>
</form>
And here's a more modern approach using a DOM library like React -
const { useState, useRef } = React
const { render } = ReactDOM
function TodoList ({ initTasks = [] })
{ const [ tasks, updateTasks ] =
useState(initTasks)
const inputEl =
useRef(null)
function onSubmit () {
updateTasks([ ...tasks, inputEl.current.value ])
inputEl.current.value = ""
}
return <div>
<h3>todo list</h3>
<ul>{tasks.map(t => <li children={t} />)}</ul>
<input ref={inputEl} placeholder="ex: paint fence" />
<button onClick={onSubmit}>add</button>
</div>
}
render
( <TodoList initTasks={[ "wash dishes", "sweep floors" ]}/>
, document.body
)
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.13.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.13.1/umd/react-dom.production.min.js"></script>

Why is this code using .parentNode not working?

Here is the method I’m trying to make. Basically what it’s supposed to do is, when an <input> with the type of button is clicked, it makes the next <div> (in this case hard-coded) go from display: none to display: block. However it’s not working.
matchDivs() {
let showInputs = document.querySelectorAll('input')
const inputs = Array.from(showInputs)
inputs.map(input => {
if (input.parentNode.getAttribute('class') === 'first-employee') {
document.querySelector('.second-employee').setAttribute('style', 'display: block')
}
return input
})
}
When you use if (node.getAttribute('class') === 'first-employee') this is return:
class='first-employee' // true
class='employee first-employee' // false
You must use:
if (node.classList.contains("first-employee")):
class='first-employee' // true
class='employee first-employee' // true
If I have understand your question properly that on button click you want to show/hide DIV tag next to it, which is inside common parent div for both, button and 'second-employee'.
I think below will be helpful.
// For single Div show/hide on button click
let btnMatchDiv = document.querySelector('#btnMatchDivs');
btnMatchDiv.addEventListener('click', matchDivs, true);
function matchDivs() {
let showInputs = document.querySelectorAll('input')
const inputs = Array.from(showInputs)
inputs.map(input => {
// Method 1
// ===========================
/*if (input.parentNode.getAttribute('class') === 'first-employee') {
document.querySelector('.second-employee').setAttribute('style', 'display: block')
}*/
// Method 2 : you can use new classList method
// ===========================
if (input.parentNode.classList.contains('first-employee')) {
input.nextElementSibling.classList.toggle('hidden');
}
//return input
})
}
body {
font-family: Arial;
}
.first-employee {
display: block;
padding: 1em;
border: 1px solid green;
}
.second-employee {
padding: 1em;
border: 1px solid red;
}
#btnMatchDivs {
padding: 1em 0.5em;
border: 1px solid #777;
}
.hidden {
display: none
}
<div class="first-employee">
<h2>
First Employee
</h2>
<input type="button" id="btnMatchDivs" value="Toggle Second Employee" />
<div class="second-employee hidden">
Second Employee
</div>
</div>
Please let me know if you need further help on this.
Thanks,
Jignesh Raval
Also if you want to toggle multiple items then you can try below code.
// For multiple Div show/hide on button click
// ===================================
let showInputs = document.querySelectorAll('input')
const btnInputs = Array.from(showInputs)
// Bind click event to each button input
btnInputs.map(input => {
input.addEventListener('click', matchDivs, false);
})
function matchDivs(event) {
let buttonEle = event.currentTarget;
if (buttonEle.parentNode.classList.contains('first-employee')) {
buttonEle.nextElementSibling.classList.toggle('hidden');
}
}
body {
font-family: Arial;
}
.first-employee {
display: block;
padding: 1em;
border: 1px solid green;
margin-bottom: 1em;
}
.second-employee {
margin: 1em 0;
padding: 1em;
border: 1px solid red;
}
#btnMatchDivs {
padding: 1em 0.5em;
border: 1px solid #777;
}
.hidden {
display: none
}
<div class="first-employee">
<h2>
First Employee 1
</h2>
<input type="button" id="btnMatchDivs" value="Match Divs" />
<div class="second-employee hidden">
Second Employee 1
</div>
</div>
<div class="first-employee">
<h2>
First Employee 2
</h2>
<input type="button" id="btnMatchDivs" value="Match Divs" />
<div class="second-employee hidden">
Second Employee 2
</div>
</div>
<div class="first-employee">
<h2>
First Employee 3
</h2>
<input type="button" id="btnMatchDivs" value="Match Divs" />
<div class="second-employee hidden">
Second Employee 3
</div>
</div>
I hope this will be helpful.
Thanks,
Jignesh Raval

Get several JSON object printed to the page

I'm making a site where the user will be able to search for a country and the city or cities in that country will show on the page. I'm able to show one city now for each country but if the country have two or more cities only one of the cities shows. I tried the "+=" to create several cards that will show on the page. That created some issues for me. I'm thinking that I have to use the "appendChild()" function to append each city card to a new div in the DOM. But i'm not 100% sure how to do that, with this code.
If I type in "USA" in the searchfield and USA both have LA and NY as cities. The first one shows now, but I want both to show. I've tried using document.createElement('cityCard') and append cityCard to the container where the cards show. But I did not get it to work as I wanted, I might have done some syntax mistake.
Is this the rigth mindset for this task? Or is it a better way?
Don't mind the CSS, its not done.
Link to a fiddle where all the code is.
https://jsfiddle.net/uzfb852g/12/
added the code under aswell(its the same as in the fiddle)
HTML CODE:
<!DOCTYPE html>
<html>
<head>
<link href="https://fonts.googleapis.com/css?family=Martel:400,700,900"
rel="stylesheet">
<link rel="stylesheet" type="text/css" href="style.css">
</head>
<body>
<h1>FINN DITT FERIESTED!</h1>
<form id="inputForm">
<input type="text" id="sokFelt">
<button id="btn">Search</button>
<button id="allBtn">Alle steder</button>
</form>
<div id="break"></div>
<div id="searchWord"></div>
<div id="cardContainer">
<div id="cityCards">
<h2 id="country"></h2>
<h4 id="city"></h4>
<img id="cityImg">
</div>
</div>
<button id="btnTwo"></button>
<script src="content.js"></script>
</body>
</html>
CSS CODE:
body{
margin: auto;
width: 100%;
height: 100%;
}
h1{
text-align: center;
margin: 25px;
color: tomato;
font-family: 'Martel', serif;
text-shadow: 1px 2px #333;
font-weight: 900;
}
#inputForm{
text-align: center;
margin: 25px;
}
#break{
width: 80%;
margin: auto;
height: 1px;
text-align: center;
background-color: #333;
}
#btn{
padding: 5px 15px;
}
#sokFelt{
padding: 5px 15px;
}
#searchWord{
font-size: 24px;
margin: 40px;
color: #333;
font-weight: bold;
}
#cardContainer{
width: 100%;
margin: auto;
display: flex;
flex-direction: column;
flex-wrap: wrap;
}
#cityCards{
padding: 12px 22px;
background-color: aqua;
border-radius: 5px;
width: 20%;
height: 250px;
}
#cityImg{
width: 100%;
height: 200px;
}
#allBtn{
padding: 5px 15px;
}
JS CODE:
var form = document.getElementById('inputForm');
var input = form.querySelector('input');
var country = document.getElementById("country");
var city = document.getElementById("city");
var cityImg = document.getElementById("cityImg");
var searchWord = document.getElementById("searchWord");
/*IMAGES*/
var place = [
{land: 'Norge', by: 'Oslo', img: 'img/Oslo.jpg'},
{land: 'USA', by: 'Los Angeles', img: "img/LA.jpg"},
{land: 'USA', by: 'New York', img: "img/NewYork.jpg"},
{land: 'Tyskland', by: 'Berlin', img: 'img/berlin.jpg'},
{land: 'Frankrike', by: 'Paris', img:'img/berlin.jpg'}
];
form.addEventListener('submit', (e) => {
e.preventDefault();
for(var i = 0; i < place.length; i += 1){
if(input.value === place[i].land) {
searchWord.innerHTML = input.value;
document.createElement('cityCards');
country.innerHTML = place[i].land;
city.innerHTML = place[i].by;
cityImg.src = place[i].img;
}
}
});
document.getElementById("btnTwo").addEventListener("click", function(){
document.createElement("")
});
Try this to see the problem:
country.innerHTML += place[i].land;
city.innerHTML += place[i].by;
citycards is not an HTML element
You must use an array with div´s (array[i]=document.createElement('div'))
Then create images with img[i] = document.createElement('img')
Set the img.src, and append this with appendChild to cardcontainer.
Using createElement and appendChild would be the right way to go, but you could also use a template tag instead.
Then you could just fill the template with the filtered information and import the template to the DOM.
Here is an example on how this could look like. You may want to take a look at the array function filter, map and forEach.
var form = document.getElementById('inputForm');
var input = form.querySelector('input');
var searchWord = document.getElementById("searchWord");
var template = document.querySelector('#cardContainer');
var getAllBtn = document.getElementById('allBtn');
var place=[{land:"Norge",by:"Oslo",img:"http://www.telegraph.co.uk/travel/destination/article137625.ece/ALTERNATES/w460/oslocityhall.jpg"},{land:"USA",by:"Los Angeles",img:"http://www.zocalopublicsquare.org/wp-content/uploads/2015/10/DistantLASkylineBIG-levinson.jpg"},{land:"USA",by:"New York",img:"https://www.city-journal.org/sites/cj/files/New-York.jpg"},{land:"Tyskland",by:"Berlin",img:"http://www.telegraph.co.uk/content/dam/Travel/Destinations/Europe/Germany/Berlin/Berlin%20cathedral-xlarge.jpg"}];
form.addEventListener('submit', (e) => {
e.preventDefault();
});
getAllBtn.addEventListener("click", function() {
// clear your container div to empty all previous added elements.
searchWord.innerHTML = "";
// filter your place data on the land property of each item.
place.filter( item => item.land === input.value )
// set the img src attr and text content for the elements in the template.
.map( item => {
template.content.getElementById("country").textContent = item.land;
template.content.getElementById("city").textContent = item.by;
template.content.getElementById("cityImg").src = item.img;
return document.importNode(template.content, true);
})
// append them to your container element.
.forEach( item => {
searchWord.appendChild(item)
})
});
body{margin:auto;width:100%;height:100%}h1{text-align:center;margin:25px;color:tomato;font-family:'Martel',serif;text-shadow:1px 2px #333;font-weight:900}#inputForm{text-align:center;margin:25px}#break{width:80%;margin:auto;height:1px;text-align:center;background-color:#333}#btn{padding:5px 15px}#sokFelt{padding:5px 15px}#searchWord{font-size:24px;margin:40px;color:#333;font-weight:700}#cardContainer{width:100%;margin:auto;display:flex;flex-direction:column;flex-wrap:wrap}#cityCards{padding:12px 22px;background-color:aqua;border-radius:5px;width:20%;height:250px}#cityImg{width:100%;height:200px}#allBtn{padding:5px 15px}
<h1>VACATION</h1>
<form id="inputForm">
<input type="text" id="sokFelt">
<button id="btn">Search</button>
<button id="allBtn">All places</button>
</form>
<div id="break"></div>
<div id="searchWord"></div>
<template id="cardContainer">
<div id="cityCards">
<h2 id="country"></h2>
<h4 id="city"></h4>
<img id="cityImg">
</div>
</template>

JavaScript: any tips on improving this code on opening/closing menu?

I've been lurking w3schools for some time and studying javaScript. I've struggled for a few days with a code of which the function is to open and then close the opened menu on click again. I couldn't do this with a single , but I've managed to it with two.
I've managed to do this with the following method:
<div id="menuClosed" style="background: blue; color: white; width: 500px; height: 50px; transition: 0.3s">
<p id="menuString" style="margin: auto; text-align:center;">
Click on the button to open the menu
</p>
<button id="menuButton" onclick="changeStyle('Closed')" style="margin-left:250px;">Open</button>
<div>
<p style="font-size: 30px; text-align:center;">Bonefish</p>
</div>
<button id="menuButton2" onclick="changeStyle('Open')" style = "margin-left:250px; display: none;">Close</button>
</div>
<script>
function changeStyle(idMenu) {
//compresses OPEN and CLOSE buttons ID into a var
var menuButton = document.getElementById("menuButton");
var menuBotton2 = document.getElementById("menuButton2");
//Compresses menu DIV's ID into a var
var menuConfig = document.getElementById("menu" + idMenu);
//styles that will serve as factor for opening/closing the menu
var style1 = "background: blue; color: white; width: 500px; height: 50px; transition: 0.3s";
var style2 = "background: blue; color: white; width: 500px; height: 150px; transition: 0.3s";
//opens Menu and changes ID to "menuOpen"
if (idMenu === "Closed") {
menuConfig.style = style2;
menuConfig.id = "menuOpen";
menuButton.style = "display: none; margin-left:250px;";
menuButton2.style = "margin-left:250px; display: initial;"
}
//Closes menu and chages ID to "menuClosed"
if (idMenu === "Open") {
menuConfig.style = style1;
menuConfig.id = "menuClosed";
menuButton.style = "display: initial; margin-left:250px;";
menuButton2.style = "margin-left:250px; display: none;";
}
}
</script>
What I actually wanted to do, is to be able to both open and close the menu with the same button, but I can't figure out how.
I believe it can be done through changing <button id="menuButton" onclick="changeStyle('Closed')" style="margin-left:250px;">Open</button> changeStyle('Closed') into changeStyle('Open') and making necessary adjustments, but, again, my tries on that have failed.
Thanks by advance.
If you could use jQuery and some css, it you'll get what you want
UPDATED WITH JAVASCRIPT
var divmenu=document.getElementById('menu');
function toggleMenu(btn){
if(btn.className=='open'){
btn.className='close';
divmenu.className='close';
btn.innerText='Open';
}else{
btn.className='open';
divmenu.className='open';
btn.innerText='Close';
}
}
div{
padding:10px 0;
color: white;
transition: 0.3s;
background: blue;
}
div.open{
height: 150px;
}
div.close{
height: 20px;
overflow:hidden;
}
<div id="menu" class="close">
<p id="menuString" style="margin: auto; text-align:center;">
Click on the button to open the menu
</p>
<p style="font-size: 30px; text-align:center;">Bonefish</p>
</div>
<p style="text-align:center; margin:0; padding:5px 0;"><button type="button" class="close" onclick="toggleMenu(this);">Open</button></p>

Categories