I need to add a click event to a css class so when clicked it switches to a different class. Specifically, I have a character class on li items that I would like to change to another class when the li item is clicked. Code:
html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<link rel="stylesheet" href="app.css" />
</head>
<body>
<div class="container">
<h1>Client Search</h1>
<div id="searchWrapper">
<input
type="text"
name="searchBar"
id="searchBar"
placeholder="search for a character"
onkeyup="myFunction()"
/>
</div>
<ul id="charactersList"></ul>
</div>
<script src="app.js"></script>
</body>
</html>
css
body {
font-family: sans-serif;
background-color: #111d4a;
}
* {
box-sizing: border-box;
}
h1 {
color: #eee;
margin-bottom: 30px;
}
.container {
padding: 40px;
margin: 0 auto;
max-width: 1000px;
text-align: center;
}
#charactersList {
padding-inline-start: 0;
display: none;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
grid-gap: 20px;
}
.character {
list-style-type: none;
background-color: #eaeaea;
border-radius: 3px;
padding: 10px 20px;
display: grid;
grid-template-columns: 3fr 1fr;
grid-template-areas:
'name image'
'house image';
text-align: left;
}
.character:hover {
background-color: blue;
cursor: pointer;
}
.character > h2 {
grid-area: name;
margin-bottom: 0px;
}
.character > p {
grid-area: house;
margin: 0;
}
#searchBar {
width: 100%;
height: 32px;
border-radius: 3px;
border: 1px solid #eaeaea;
padding: 5px 10px;
font-size: 12px;
}
#searchWrapper {
position: relative;
}
#searchWrapper::after {
content: '🔍';
position: absolute;
top: 7px;
right: 15px;
}
javaScript
const charactersList = document.getElementById('charactersList');
const searchBar = document.getElementById('searchBar');
let clientNames = [];
searchBar.addEventListener('keyup', (e) => {
const searchString = e.target.value.toLowerCase();
const filteredCharacters = clientNames.filter((character) => {
return (
character.name.toLowerCase().includes(searchString) ||
character.house.toLowerCase().includes(searchString)
);
});
displayCharacters(filteredCharacters);
});
const loadCharacters = async () => {
try {
const res = await fetch('https://hp-api.herokuapp.com/api/characters');
clientNames = await res.json();
displayCharacters(hpCharacters);
} catch (err) {
console.error(err);
}
};
const displayCharacters = (characters) => {
const htmlString = characters
.map((character) => {
return `
<li class="character">
<h2>${character.name}</h2>
<p>House: ${character.house}</p>
</li>
`;
})
.join('');
charactersList.innerHTML = htmlString;
};
loadCharacters();
//change the display of characterListfrom none to grid
function myFunction() {
var charactersList = document.getElementById("charactersList");
charactersList.style.display = "grid";
//also check if searchBar is empty and set display back to none
var searchBar = document.getElementById("searchBar").value;
if (searchBar === ""){
charactersList.style.display = "none";
}
}
Great question!
I just made a CodePen to illustrate how to programmatically change CSS class names when a li item is clicked. Check out this example and let me know if this clarifies the problem : )
JS
let list = document.getElementById('myList');
let items = ['First', 'Second', 'Third', 'Fourth', 'Fifth'];
for(let item of items){
let li = document.createElement("LI");
li.appendChild(document.createTextNode(item));
li.classList.add('blue');
li.addEventListener("click", () => {
li.classList.remove('blue');
li.classList.add('red');
});
list.appendChild(li);
}
HTML
<ul id="myList"></ul>
CSS
.blue{
color: blue;
}
.red{
color: red;
}
https://codepen.io/CrowlsYung/pen/eYJRPjx
Suggested Change
<li class="character" onclick="handleItemClick(event)">
<h2>${character.name}</h2>
<p>House: ${character.house}</p>
</li>
function handleItemClick(e){
e.currentTarget.classList.toggle('prevClass')
e.currentTarget.classList.toggle('newClass');
}
Related
First of all i want to point out that i saw that there are similar posts about tracking event listeners but in my case i just couldn't figure it out. I am familliar with event.target property but in my case i just couldn't make it.
So this is my code snippet:
const taskListSection = document.querySelector('.task-list-section');
const taskListAddModal = document.querySelector('.task-list-add-modal');
const confirmTaskAddBtn = document.getElementById('add-list');
const cancelTaskAddBtn = document.getElementById('cancel-add-list');
const addTaskBtn = document.getElementById('add-task');
const titleInput = document.getElementById('title');
const descriptionInput = document.getElementById('description');
const timeInput = document.getElementById('time');
const clearUserInput = () => {
titleInput.value = '';
descriptionInput.value = '';
timeInput.value = '';
};
const taskListAddModalHandler = () => {
const taskList = taskListSection.querySelectorAll('li');
taskListAddModal.classList.toggle('visible');
addTaskBtn.classList.toggle('visible');
taskList.forEach((list) => {
list.classList.toggle('visible');
});
clearUserInput();
};
const confirmAddTask = () => {
const newTask = document.createElement('li');
const taskList = taskListSection.querySelectorAll('li');
const titleInputValue = titleInput.value;
const descriptionInputValue = descriptionInput.value;
const timeInputValue = timeInput.value;
if(titleInputValue.trim() === ''){
alert('Please enter a title of your task!');
return;
}
newTask.className = 'visible';
newTask.innerHTML =
`<button class="check-task">C</button>
<button class="remove-task">X</button>
<h4>Title:</h4>
<p>${titleInputValue}</p>
<h4>Description:</h4>
<p>${descriptionInputValue}</p>
<h4>Time:</h4>
<p>${timeInputValue}</p>`;
taskListSection.append(newTask);
taskListAddModal.classList.remove('visible');
taskList.forEach((list) => {
list.classList.add('visible');
});
addTaskBtn.classList.toggle('visible');
clearUserInput();
};
addTaskBtn.addEventListener('click', taskListAddModalHandler);
cancelTaskAddBtn.addEventListener('click', taskListAddModalHandler);
confirmTaskAddBtn.addEventListener('click', confirmAddTask);
body{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.main-wrapper{
width: 70rem;
margin: 0 auto;
border: 2px solid black;
position: relative;
}
.main-wrapper #add-task{
display: none;
}
.main-wrapper #add-task.visible{
position: absolute;
top: 150px;
right: 100px;
width: 50px;
height: 50px;
font-size: 50px;
display: flex;
justify-content: center;
align-items: center;
}
ul{
border: 1px solid black;
width: 40rem;
height: 40rem;
margin: 10rem auto;
padding: 0;
background-color: red;
overflow-x: scroll;
}
ul form{
flex-direction: column;
width: 100%;
height: 40rem;
background-color: white;
display: none;
}
ul form input[type=button]{
display: block;
margin: 10px auto;
}
ul form.visible{
display: flex;
}
ul li{
display: none;
}
ul li.visible{
display: block;
width: 80%;
list-style: none;
border: 2px solid black;
margin: 10px;
position: relative;
}
ul li .check-task{
position: absolute;
width: 30px;
height: 30px;
top: 30px;
right: 30px;
}
ul li .remove-task{
position: absolute;
width: 30px;
height: 30px;
bottom: 30px;
right: 30px;
}
ul li.checked{
background-color: green;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section class="main-wrapper">
<button id="add-task" class="visible">+</button>
<ul class="task-list-section">
<form class="task-list-add-modal">
<label for="title">Title:</label>
<input type="text" id="title">
<label for="description">Description:</label>
<textarea type="text" id="description" maxlength="100"></textarea>
<label for="time">Time:</label>
<input type="text" id="time">
<div class="to-do-list-confirmation">
<input type="button" id="add-list" value="ADD">
<input type="button" id="cancel-add-list" value="CANCEL">
</div>
</form>
</ul>
</section>
<script src="app.js"></script>
</body>
</html>
I have a problem to track which button 'C' on which 'li' element was clicked. So the logic behind this would be that when i click on 'C' button on certain li element that was created i want THAT 'li' element to get class named 'checked' (class 'checked' will provide green background to that 'li' element). You create 'li' element by clicking a "+" button on your top right corner than filling input elements and then by clicking ADD button. Sorry about lousy design i made it really fast just to try and explain what is my problem. I would like you to give me solution using pure JS. Thanks in advance.
Since you asked for an example, the following example is simplified to show how you can use an event parameter in your handler function to be used on the element that is being triggered in your listener. This is over simplified to show you how it is done. You will need to apply this functionality to your code, it is rather easy once you understand the concept.
Further notes in the code snippit below...
// here I am querying all the buttons in the dom
let el = document.querySelectorAll("button");
// I am running them through a loop and applying an event listner with a handler function on click
for(let i = 0; i < el.length; i++){
el[i].addEventListener('click', handler);
}
// the function passes a parameter "event" => e.
// we use the e.target to get the element being pressed
// I use a data attribute in the element being pressed
// to locate an id and affect its background color
function handler(e){
let handler = e.target.getAttribute("data-handler");
let target = document.getElementById(handler);
target.style.backgroundColor = '#d4d4d4';
}
<div id="one">Div One</div>
<div id="two">Div Two</div>
<div id="three">Div Three</div>
<div id="four">Div Four</div>
<button data-handler="one">This btn handles div one</button>
<button data-handler="two">This btn handles div two</button>
<button data-handler="three">This btn handles div three</button>
<button data-handler="four">This btn handles div four</button>
Yeah my problem was that my 'li' elements were not premade so to say, like in your example. They were created with JS so i couldnt figure out how to 'connect' button and his li element and then use target property (like you did with data-handler and id of div element). But i found a way by giving random id to my li element by using Math.random and then i used that same number as data-handler value on my button and then rest was easy. Thanks a lot you gave me a little push so i made it. It works. Here is a code snippet may be useful to someone.
const taskListSection = document.querySelector('.task-list-section');
const taskListAddModal = document.querySelector('.task-list-add-modal');
const confirmTaskAddBtn = document.getElementById('add-list');
const cancelTaskAddBtn = document.getElementById('cancel-add-list');
const addTaskBtn = document.getElementById('add-task');
const titleInput = document.getElementById('title');
const descriptionInput = document.getElementById('description');
const timeInput = document.getElementById('time');
const clearUserInput = () => {
titleInput.value = '';
descriptionInput.value = '';
timeInput.value = '';
};
const taskListAddModalHandler = () => {
const taskList = taskListSection.querySelectorAll('li');
taskListAddModal.classList.toggle('visible');
addTaskBtn.classList.toggle('visible');
taskList.forEach((list) => {
list.classList.toggle('visible');
});
clearUserInput();
};
const confirmAddTask = () => {
const newTask = document.createElement('li');
const taskList = taskListSection.querySelectorAll('li');
const titleInputValue = titleInput.value;
const descriptionInputValue = descriptionInput.value;
const timeInputValue = timeInput.value;
if(titleInputValue.trim() === ''){
alert('Please enter a title of your task!');
return;
}
newTask.className = 'visible';
let newTaskId = newTask.id = Math.random().toString();
newTask.innerHTML =
`<button data-handler = '${newTaskId}' class="check-task">C</button>
<button data-handler = '${newTaskId}' class="remove-task">X</button>
<h4>Title:</h4>
<p>${titleInputValue}</p>
<h4>Description:</h4>
<p>${descriptionInputValue}</p>
<h4>Time:</h4>
<p>${timeInputValue}</p>`;
taskListSection.append(newTask);
taskListAddModal.classList.remove('visible');
taskList.forEach((list) => {
list.classList.add('visible');
});
const checkTaskBtn = document.querySelectorAll('.check-task');
for(const btn of checkTaskBtn){
btn.addEventListener('click', taskCheck);
}
addTaskBtn.classList.toggle('visible');
clearUserInput();
};
const taskCheck = (e) => {
let handler = e.target.getAttribute("data-handler");
let target = document.getElementById(handler);
target.classList.toggle('checked');
}
addTaskBtn.addEventListener('click', taskListAddModalHandler);
cancelTaskAddBtn.addEventListener('click', taskListAddModalHandler);
confirmTaskAddBtn.addEventListener('click', confirmAddTask);
body{
margin: 0;
padding: 0;
box-sizing: border-box;
}
.main-wrapper{
width: 70rem;
margin: 0 auto;
border: 2px solid black;
position: relative;
}
.main-wrapper #add-task{
display: none;
}
.main-wrapper #add-task.visible{
position: absolute;
top: 150px;
right: 100px;
width: 50px;
height: 50px;
font-size: 50px;
display: flex;
justify-content: center;
align-items: center;
}
ul{
border: 1px solid black;
width: 40rem;
height: 40rem;
margin: 10rem auto;
padding: 0;
background-color: red;
overflow-x: scroll;
}
ul form{
flex-direction: column;
width: 100%;
height: 40rem;
background-color: white;
display: none;
}
ul form input[type=button]{
display: block;
margin: 10px auto;
}
ul form.visible{
display: flex;
}
ul li{
display: none;
}
ul li.visible{
display: block;
width: 80%;
list-style: none;
border: 2px solid black;
margin: 10px;
position: relative;
}
ul li .check-task{
position: absolute;
width: 30px;
height: 30px;
top: 30px;
right: 30px;
}
ul li .remove-task{
position: absolute;
width: 30px;
height: 30px;
bottom: 30px;
right: 30px;
}
ul li.checked{
background-color: green;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
<link rel="stylesheet" href="style.css">
</head>
<body>
<section class="main-wrapper">
<button id="add-task" class="visible">+</button>
<ul class="task-list-section">
<form class="task-list-add-modal">
<label for="title">Title:</label>
<input type="text" id="title">
<label for="description">Description:</label>
<textarea type="text" id="description" maxlength="100"></textarea>
<label for="time">Time:</label>
<input type="text" id="time">
<div class="to-do-list-confirmation">
<input type="button" id="add-list" value="ADD">
<input type="button" id="cancel-add-list" value="CANCEL">
</div>
</form>
</ul>
</section>
<script src="app.js"></script>
</body>
</html>
I'm making a To-Do List and trying to remove an item when I click a trash bin icon
image
not only the item but also its data from local storage.
However, when I click the icon, only one data is removed.
If I remove another 'li' tag, I have to refresh my page and then click it.
I want to remove items and data, do not refresh it
What is the problem with my page?
Thank you.
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>TO DO LIST</title>
<link rel="stylesheet" href="style.css" />
<link
rel="stylesheet"
href="https://use.fontawesome.com/releases/v5.13.1/css/all.css"
integrity="sha384-xxzQGERXS00kBmZW/6qxqJPyxW3UR0BPsL4c8ILaIWXva5kFi7TxkIIaMiKtqV1Q"
crossorigin="anonymous"
/>
<script src="main.js" defer></script>
<!-- <script src="data_storage.js" defer></script> -->
</head>
<body>
<section class="container">
<h1>TO DO LIST</h1>
<ul></ul>
<div class="footer">
<input type="text" placeholder="Title..." />
<button class="enter">Enter</button>
</div>
</section>
</body>
</html>
CSS
* {
font-family: Arial, Helvetica, sans-serif;
}
body {
background-color: #ecf0f1;
}
.container {
width: 50%;
height: 100%;
margin: auto;
border: 1px solid green;
border-radius: 15px 15px 0 0;
}
h1 {
margin: 10px 20px;
padding-bottom: 15px;
text-align: center;
font-size: 42px;
color: #98e3a1;
border-bottom: 1px dotted #5e7361;
}
ul {
font-size: 24px;
padding-bottom: 10px;
list-style-type: none;
}
li {
position: relative;
padding-bottom: 8px;
margin-bottom: 3px;
margin-right: 20px;
border-bottom: 1px solid grey;
}
.footer {
display: block;
position: relative;
}
input {
position: relative;
width: 93%;
padding: 10px 0;
border: none;
outline: none;
}
.enter {
position: absolute;
padding: 0;
width: 7%;
height: 100%;
outline: none;
background-color: greenyellow;
border: none;
color: grey;
}
.fas {
font-size: 20px;
position: absolute;
right: 10px;
top: 10px;
cursor: pointer;
transition: transform 200ms ease-in;
}
.fas:hover {
color: red;
transform: scale(1.1);
}
JavaScript
const ul = document.querySelector("ul");
const input = document.querySelector("input");
const enterBtn = document.querySelector(".enter");
const LIST_LS = "lists";
function filterFn(toDo) {
return toDo.id === 1;
}
let lists = [];
function saveStorage() {
localStorage.setItem(LIST_LS, JSON.stringify(lists));
}
function deleteStorage(event) {
const trashBtn = event.target;
const li = trashBtn.parentNode;
ul.removeChild(li);
const cleanStorage = lists.filter((toDo) => {
return toDo.id !== parseInt(li.id);
});
lists = cleanStorage;
saveStorage();
}
function loadStorage() {
const loadStorage = localStorage.getItem(LIST_LS);
if (loadStorage !== null) {
const parsedList = JSON.parse(loadStorage);
parsedList.forEach((list) => {
createItem(list.text);
});
}
}
function onAdd() {
const text = input.value;
if (text === "") {
input.focus();
return;
}
createItem(text);
input.value = "";
input.focus();
}
function createItem(text) {
const itemRow = document.createElement("li");
const newId = lists.length + 1;
itemRow.setAttribute("class", "item__row");
itemRow.innerHTML = `${text} <i class="fas fa-trash-alt" data-id=${itemRow.id}></i>`;
ul.appendChild(itemRow);
itemRow.id = newId;
const delBtn = document.querySelector(".fa-trash-alt");
delBtn.addEventListener("click", deleteStorage);
const listObj = {
text: text,
id: newId,
};
lists.push(listObj);
saveStorage();
return itemRow;
}
loadStorage();
enterBtn.addEventListener("click", () => {
onAdd();
});
input.addEventListener("keypress", (event) => {
if (event.key === "Enter") onAdd();
});
Your problem is this line:
const delBtn = document.querySelector(".fa-trash-alt");
This means it will always select the first trash icon.
You have to write:
const delBtn = itemRow.querySelector(".fa-trash-alt");
Working example here:
https://codesandbox.io/s/damp-morning-csiny
I want to add an event listener or something similar that changes the display of the character class in CSS from none to grid when a key is typed in the searchbar.
I've tried several ways but am not having much luck and am not quite sure how to work it in. I would also like to make the elements clickable. Any help would really be appreciated. Code
HTML
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>Document</title>
<link rel="stylesheet" href="app.css" />
</head>
<body>
<div class="container">
<h1>✨Harry Potter Characters ✨</h1>
<div id="searchWrapper">
<input
type="text"
name="searchBar"
id="searchBar"
placeholder="search for a character"
/>
</div>
<ul id="charactersList"></ul>
</div>
<script src="app.js"></script>
</body>
</html>
CSS
body {
font-family: sans-serif;
background-color: #111d4a;
}
* {
box-sizing: border-box;
}
h1 {
color: #eee;
margin-bottom: 30px;
}
.container {
padding: 40px;
margin: 0 auto;
max-width: 1000px;
text-align: center;
}
#charactersList {
padding-inline-start: 0;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(320px, 1fr));
grid-gap: 20px;
}
.character {
list-style-type: none;
background-color: #eaeaea;
border-radius: 3px;
padding: 10px 20px;
display: none;
grid-template-columns: 3fr 1fr;
grid-template-areas:
"name"
"house";
text-align: left;
}
.hide {
display: none;
}
.character > h2 {
grid-area: name;
margin-bottom: 0px;
}
.character > p {
grid-area: house;
margin: 0;
}
#searchBar {
width: 100%;
height: 32px;
border-radius: 3px;
border: 1px solid #eaeaea;
padding: 5px 10px;
font-size: 12px;
}
#searchWrapper {
position: relative;
}
#searchWrapper::after {
content: "🔍";
position: absolute;
top: 7px;
right: 15px;
}
JS
const charactersList = document.getElementById("charactersList");
const searchBar = document.getElementById("searchBar");
let hpCharacters = [];
searchBar.addEventListener("keyup", (e) => {
const searchString = e.target.value.toLowerCase();
const filteredCharacters = hpCharacters.filter((character) => {
return character.name.toLowerCase().includes(searchString);
});
displayCharacters(filteredCharacters);
});
const loadCharacters = async () => {
try {
const res = await fetch("https://hp-api.herokuapp.com/api/characters");
hpCharacters = await res.json();
displayCharacters(hpCharacters);
} catch (err) {
console.error(err);
}
};
const displayCharacters = (characters) => {
const htmlString = characters
.map((character) => {
return `
<li class="character">
<h2>${character.name}</h2>
<p>House: ${character.house}</p>
</li>
`;
})
.join("");
charactersList.innerHTML = htmlString;
};
loadCharacters();
So
So I want to add an event listener or something similar that changes the display of the display of the "character" class in css from "none" to "grid" when a key is typed in the searchbar.
You could do this by applying an eventlistener i.e the keypress event listener - and on that functions callback just use the element.classlist.toggle or element.classlist.add to add another class to the element which has the display of grid.
another method would also to be use the event listener for the keypress of your choice, but in the call back, edit the style of the element in question - so
addEventListener('keypress', function (e) {
if (e.key === 'Enter') {
element.style.display="grid";
// to make the element clickable - just add another event listener to it -
}
});
For any key being pressed the event listener is keydown -
https://developer.mozilla.org/en-US/docs/Web/API/Document/keydown_event
addEventListener('keydown', function (e) {
element.style.display="grid";
});
Hope that helps -
W
So I'm making a calculator in JavaScript as a way to learn JavaScript. I'd like to add some sort of Object Orientated into the project.
My HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<title>The Unconventional Calculator</title>
<link
href="https://fonts.googleapis.com/css?family=Roboto:400,700&display=swap"
rel="stylesheet"
/>
<link rel="stylesheet" href="assets/styles/app.css" />
</head>
<body>
<header>
<h1>The Unconventional Calculator</h1>
</header>
<section id="calculator">
<input type="number" id="input-number" />
<div id="calc-actions">
<button type="button" id="btn-add">+</button>
<button type="button" id="btn-subtract">-</button>
<button type="button" id="btn-multiply">*</button>
<button type="button" id="btn-divide">/</button>
<button type="button" id="btn-equals">=</button>
</div>
</section>
<section id="results">
<h2 id="current-calculation">0</h2>
<h2>Result: <span id="current-result">0</span></h2>
</section>
<section class="credit">
<h1>Check out my code on GitHub
<br>Type your number, press enter, repeat until you're done and then press enter.</h1>
</section>
<!-- So the site loads first then the js runs -->
<script src="assets/scripts/vendor.js"></script>
<script src="assets/scripts/app.js"> </script>
</body>
</html>
MY CSS
* {
box-sizing: border-box;
}
html {
font-family: 'Roboto', open-sans;
}
body {
margin: 0;
}
header {
background: #6d0026;
color: white;
padding: 1rem;
text-align: center;
box-shadow: 0 2px 8px rgba(0, 0, 0, 0.26);
width: 100%;
}
#results,
#calculator {
margin: 2rem auto;
width: 40rem;
max-width: 90%;
border: 1px solid #6d0026;
border-radius: 10px;
padding: 1rem;
color: #6d0026;
}
#results {
text-align: center;
}
#calculator input {
font: inherit;
font-size: 3rem;
border: 2px solid #6d0026;
width: 10rem;
padding: 0.15rem;
margin: auto;
display: block;
color: #6d0026;
text-align: center;
}
#calculator input:focus {
outline: none;
}
#calculator button {
font: inherit;
background: #6d0026;
color: white;
border: 1px solid #6d0026;
padding: 1rem;
cursor: pointer;
}
#calculator button:focus {
outline: none;
}
#calculator button:hover,
#calculator button:active {
background: #6d2d1b;
border-color: #6d2d1b;
}
#calc-actions button {
width: 4rem;
}
#calc-actions {
margin-top: 1rem;
text-align: center;
}
.credit {
margin: 70px 0 0 0;
text-align: center;
}
app.js
// Base Variables
let result = 0;
let number = 0;
//Store equation as string
let calculationDescription = "";
//Event listeners
document.querySelector("#btn-add").addEventListener('click', sumNumbs);
document.querySelector("#btn-subtract").addEventListener('click', subtractNumbs);
document.querySelector("#btn-multiply").addEventListener('click', multiplyNumbs);
document.querySelector("#btn-divide").addEventListener('click', divideNumbs);
document.querySelector("#btn-equals").addEventListener('click', equals);
document.querySelector('#input-number').addEventListener('keypress', numbersInput);
function numbersInput(e) {
if(e.key === 'Enter' && userInput !== null) {
number = e.target.value;
e.target.value = '';
calculationDescription += number + " ";
console.log(calculationDescription);
}
}
function sumNumbs() {
calculationDescription += "+ ";
}
function subtractNumbs() {
calculationDescription += "- ";
}
function multiplyNumbs() {
calculationDescription += "x ";
}
function divideNumbs() {
calculationDescription += "/ ";
}
function equals() {
let finalCalculation = calculationDescription.split(" ");
//Goes to errorHandler to remove whitespace and make array ready for equation
errorHandler.removeWhiteSpace(finalCalculation);
}
errorHandler.js
class errorHandler {
static removeWhiteSpace(arraySplit) {
return console.log(arraySplit);
}
}
vendor.js(this one isn't to important for the solution)
const userInput = document.getElementById('input-number');
const addBtn = document.getElementById('btn-add');
const subtractBtn = document.getElementById('btn-subtract');
const multiplyBtn = document.getElementById('btn-multiply');
const divideBtn = document.getElementById('btn-divide');
const equalsBtn = document.getElementById('btn-equals');
const currentResultOutput = document.getElementById('current-result');
const currentCalculationOutput = document.getElementById('current-calculation');
function outputResult(result, text) {
currentResultOutput.textContent = result;
currentCalculationOutput.textContent = text;
}
So in my equals method I'd like to send the array finalCalculation which is in the app.js class into the removeWhiteSpace method that's in my errorHandler.js
This is the error I keep getting
app.js:44 Uncaught ReferenceError: errorHandler is not defined
at HTMLButtonElement.equals (app.js:44)
I've tried turning both of them into classes and then creating a constructor with an instance variable for errorHandler to take in the array, but that doesn't seem to work.
I'm creating a currency converter app using html,css and javascript, and when text is entered into the <input> on the left, the converted value will appear in the input element on the right: <p id = "converted">.
I want to keep the underline(border-bottom) the same length on the <p id = "converted">. Currently, when you enter text into the input element on the left, the one on the right increases in size and makes the underline larger. I want the underline to stay the same as when there is no text in the element.
I am currently styling the <p id = "converted"> element like so:
padding-right: 40%;
border-bottom: 0.5vh solid white;
I do not think the API I am using will work correctly with the stack overflow snippets, but I will include a link to a codepen: https://codepen.io/oliknight/pen/XLvQow
let currlet currencyArr = [];
let ratesArr = [];
window.addEventListener("load", () => {
const api = "https://api.exchangeratesapi.io/latest?base=GBP";
fetch(api)
.then(response => {
return response.json();
})
.then(data => {
for (currency in data.rates) {
currencyArr.push(currency);
ratesArr.push(data.rates[currency]);
// create 'option' element here
var optionLeft = document.createElement("option");
var optionRight = document.createElement("option");
optionLeft.textContent = currency;
optionRight.textContent = currency;
document.querySelector("#left-select").appendChild(optionLeft);
document.querySelector("#right-select").appendChild(optionRight);
}
document.querySelector("#input").addEventListener("keyup", convert);
function convert() {
const input = document.querySelector("#input");
let leftSelectValue = document.querySelector("#left-select").value;
let convertedNumber = document.querySelector("#converted");
for (let i = 0; i < currencyArr.length; i++) {
if (leftSelectValue === currencyArr[i]) {
convertedNumber.textContent = ratesArr[i].toFixed(4) * input.value;
}
}
}
});
});
encyArr = [];
let ratesArr = [];
window.addEventListener("load", () => {
const api = "https://api.exchangeratesapi.io/latest?base=GBP";
fetch(api)
.then(response => {
return response.json();
})
.then(data => {
for (currency in data.rates) {
currencyArr.push(currency);
ratesArr.push(data.rates[currency]);
// create 'option' element here
var optionLeft = document.createElement("option");
var optionRight = document.createElement("option");
optionLeft.textContent = currency;
optionRight.textContent = currency;
document.querySelector("#left-select").appendChild(optionLeft);
document.querySelector("#right-select").appendChild(optionRight);
}
document.querySelector("#input").addEventListener("keyup", convert);
function convert() {
const input = document.querySelector("#input");
let leftSelectValue = document.querySelector("#left-select").value;
let convertedNumber = document.querySelector("#converted");
for (let i = 0; i < currencyArr.length; i++) {
if (leftSelectValue === currencyArr[i]) {
convertedNumber.textContent = ratesArr[i].toFixed(4) * input.value;
}
}
}
});
});
html {
font-family: "Lato", sans-serif;
font-weight: thin;
background-image: linear-gradient(to right top, #90d0ff, #008ef7);
color: white;
height: 100vh;
overflow: hidden;
}
h1 {
text-align: center;
font-size: 5em;
position: absolute;
left: 0;
right: 0;
margin: auto;
}
.container {
width: 50%;
display: flex;
justify-content: center;
align-items: center;
}
.container p {
font-size: 8em;
display: inline-block;
padding-right: 40%;
border-bottom: 0.5vh solid white;
max-width: 50%;
}
.parent {
display: flex;
justify-content: center;
height: 100vh;
align-items: center;
}
.container select {
background: transparent;
color: white;
padding: 20px;
width: 80px;
height: 60px;
border: none;
font-size: 20px;
box-shadow: 0 5px 25px rgba(0, 0, 0, 0.5);
-webkit-appearance: button;
outline: none;
margin-left: 10%;
}
.original {
background: transparent;
border: none;
border-bottom: 0.5vh solid white;
font-size: 8em;
max-width: 50%;
outline: none;
font-family: "Lato", sans-serif;
font-weight: thin;
color: white;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<title>Currency Converter</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
<link rel="stylesheet" href="main.css" />
<link href="https://fonts.googleapis.com/css?family=Lato:300&display=swap" rel="stylesheet" />
</head>
<body>
<h1>Currency Converter</h1>
<div class="parent">
<div class="container">
<input type="text" class="original" id="input" />
<select id="left-select"> </select>
</div>
<div class="container" id="ctn">
<p id="converted">0</p>
<select id="right-select"> </select>
</div>
</div>
<script src="main.js"></script>
</body>
</html>
Thanks!
If you replace max-width with width in your css, the percentage (e.g. 50%) width will stay the same, regardless of how long the converted number is. However this poses a problem regarding your overflow.
You could remove the padding, but you could still run into issues whereby only half a digit is showing at the end, depending on how big the device is:
So you may want to either reduce the font size or experiment with width percentages (maybe 49 or 51 .. ) , or both ..
If you knew exactly how many decimal digits there would be in the returned converted number, this would help determine an adequate size font.
Good luck, and hope this helps