I am trying to build a simple webpage, which simply checks the value of the strings in two input fields, such that when the Test button is clicked, a previously hidden div will show the boolean value to be returned (If isomorphic return true, else, return false).
This is my code:
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Isomorphics App</title>
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" type="text/css" media="screen" href="styles.css" />
</head>
<body>
<div class="container">
<div class="content">
<div class="header">
<p class="title">Isomorphics</p>
<span> </span>
<p class="description">Find out if any two strings are isomorphic.</p>
<span> </span>
<p>Enter any two words (strings) in the fields below:</p>
</div>
<div class="input-container">
<input class="input" id="s" placeholder="First string" />
<input class="input" id="t" placeholder="Second string" />
<button class="input-button" id="submit-button">Test</button>
</div>
<div class="isomorphic-state-container" id="isomorphic-state-container">
<div class="isomorphic-state-holder" id="isomorphic-state-holder">
<p class="isomorphic-state" id="isomorphic-state">ili</p>
</div>
</div>
</div>
</div>
<script src="main.js"></script>
</body>
</html>
main.js
let s = document.getElementById('s').innerText;
let t = document.getElementById('t').innerText;
console.log(s);
document.getElementById('submit-button').onclick = isomorphic(s, t);
console.log(isomorphic(s, t));
function isomorphic(str1, str2) {
if (str1.length !== str2.length) {
alert('Please enter two strings of equal length.');
}
let map = {};
for (let i = 0; i < str1.length; i++){
let a = str1[i];
let b = str2[i];
if (typeof map[a] === 'undefined') {
map[a] = b;
} else if (map[a] !== b) {
// alert(false);
document.getElementById('isomorphic-state-container').style.display = 'block';
document.getElementById('isomorphic-state-holder').style.backgroundColor = 'red';
document.getElementById('isomorphic-state').innerText = 'False'
}
for (var key in map) {
if (key !== a && b === map[key]) {
// alert(false);
document.getElementById('isomorphic-state-container').style.display = 'block';
document.getElementById('isomorphic-state-holder').style.backgroundColor = '#D64BFB';
document.getElementById('isomorphic-state').innerText = 'False'
}
}
}
document.getElementById('isomorphic-state-container').style.display = 'block';
document.getElementById('isomorphic-state-holder').style.backgroundColor = 'green';
document.getElementById('isomorphic-state').innerText = 'True'
}
styles.css
* {
margin: 0;
padding: 0;
box-sizing: border-box;
font-family: Roboto Mono;
font-size: 16px;
}
*:focus {
outline: none;
}
.header {
color: #FFFFFF;
text-align: center;
}
.header .title {
font-size: 36px;
}
.header .description {
font-size: 16px;
}
.container {
display: flex;
align-items: center;
justify-content: center;
height: 100vh;
width: 100vw;
background-color: #000000;
}
.container .content {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
height: 65%;
width: 100%;
}
.container .content .input-container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: space-around;
width: 50%;
height: 150px;
}
.container .content .input-container .input {
width: 100%;
height: 40px;
font-size: 16px;
padding-left: 10px;
}
.container .content .input-container .input-button {
width: 100%;
height: 40px;
background-color: rgba(255, 255, 255, 0.1);
color: #FFFFFF;
font-size: 16px;
}
.container .content .input-container .input-button:hover {
cursor: pointer;
}
.isomorphic-state-container {
display: none;
width: 50%;
height: 40px;
}
.isomorphic-state-holder {
width: 100%;
height: 100%;
display: flex;
align-items: center;
justify-content: center;
}
.isomorphic-state {
color: #FFFFFF;
font-size: 16px;
}
After running this code, the javascript defaults the value to true, and doesn't work even when I click the button. Screenshot:
What should I do to make the code run only when the button is clicked? Or, is the named function causing the problem?
This line:
document.getElementById('submit-button').onclick = isomorphic(s, t);
calls your function and then assigns its return value to onclick, exactly the way x = foo() calls foo and assigns its result to x. To set a click event handler that way, you assign a function (not its result) to the onclick property, for instance:
document.getElementById('submit-button').onclick = function() {
isomorphic(s, t);
};
(You'll also want to remove the console.log(isomorphic(s, t)); line, since it also calls the function.)
If you want to get s and t as of when the button is clicked, instead of when the script first runs, move those lines into the click handler as well:
document.getElementById('submit-button').onclick = function() {
let s = document.getElementById('s').innerText;
let t = document.getElementById('t').innerText;
isomorphic(s, t);
};
Better yet, use modern event handling via addEventListener:
document.getElementById('submit-button').addEventListener("click", function() {
// ...handler code...
});
If you need to support obsolete browsers like IE8, this answer has a workaround to their lack of addEventListener support.
There are several other issues with your code, though. For instance, to get the value of an input element, you use its value property, not its innerText property (it doesn't have any inner text, because it's a void element). You're also not returning after your alert about unequal string lengths, which you probably want to do since otherwise you go ahead and run the body of the function even though you did the alert...
Related
So I created a 16 x 16 grid where I can etch a sketch on that grid. It's working well. Right now, I have to call the function createGrid(number) everytime I want to change the size of the grid. I have created a text input boxes as you can see on my code. So instead of having to write it again everytime and refresh the page, I want to be able to use the input from this box to change the size of the grid.
One of the ways that I've tried is by creating a new variable such as:
let number = inputFromBox.value;
and then write createGrid(number) . But it doesn't work. Is there any way how to make this work ? by using the input from the box ? Please help. Thank you !
let container = document.querySelector('.container');
let rows = document.getElementsByClassName('gridRow');
let duplicateOfInput = document.getElementById('duplicateOfInput');
let button = document.getElementById('submit');
let inputFromBox = document.getElementsByClassName('size-box');
button.addEventListener('click', createGrid);
createGrid(16);
draw();
// createGrid(anyNumber);
// draw();
// duplicateOfInput.textContent = `${input}`;
// const rainbow = document.getElementsByClassName('rainbow');
let reset = document.getElementById('clear-button');
reset.addEventListener('click', clearGrid);
function createGrid(number) {
makeRow(number);
makeColumn(number);
draw();
}
function makeRow(numberOfRow) {
container.innerHTML = "";
for (let i = 0; i <numberOfRow; i++) {
let row = document.createElement('div');
container.appendChild(row);
row.classList.add('gridRow');
}
}
function makeColumn(numberOfColumn) {
for ( let i = 0; i < rows.length; i++) {
for ( let j = 0; j < numberOfColumn; j++) {
let column = document.createElement('div');
rows[j].appendChild(column);
column.classList.add('gridColumn');
}
}
}
//adds event listener to all divs with class "column"
//added in global scope to allow drawing on page load
//this refers to the element triggering the mouseover event listener
function draw() {
let columns = document.getElementsByClassName("gridColumn");
for (let i = 0; i < columns.length; i++) {
columns[i].addEventListener("mouseover", changeColor);
}
function changeColor() {
let blue = document.getElementById('blue');
let eraser = document.getElementById('eraser');
let black = document.getElementById('black');
let rainbow = document.getElementById('rainbow');
if (blue.checked) {
this.style.backgroundColor = 'blue';
} else if (eraser.checked) {
this.style.backgroundColor = 'beige';
} else if (black.checked) {
this.style.backgroundColor = 'black';
} else if (rainbow.checked) {
let randomColor = Math.floor(Math.random()*16777215).toString(16);
this.style.backgroundColor = '#' + randomColor;
}
}
}
//eraser function loops through all column divs and sets background to "" in DOM
function clearGrid() {
let columns = document.getElementsByClassName("gridColumn");
for (let i = 0; i < columns.length; i++) {
columns[i].style.backgroundColor = '';
}
}
#import url('https://fonts.googleapis.com/css2?family=Asap:wght#400;600;700&display=swap');
body {
display: flex;
height: 100%;
width: 100%;
flex-direction: column;
background-color: beige;
font-family: Asap, sans-serif;
margin: 0;
padding: 0;
justify-content: center;
align-content: center;
align-items: center;
background-repeat: no-repeat;
}
.header {
display: flex;
flex: 1;
justify-content: center;
}
#header-title {
font-family: Asap, sans-serif;
font-size: 18px;
}
#setGridSize {
display: inline-flex;
justify-content: center;
align-items: center;
flex: 1;
gap: 12px;
}
#guide {
text-align: center;
margin: 1px;
font-family: Asap, sans-serif;
color: red;
font-size: 13px;;
}
.canvas {
display: flex;
justify-content: center;
align-items: center;
}
.container {
display: flex;
flex-direction: column;
border: 1px solid green;
width: 550px;
height: 550px;
}
/* .gridColumn {
display: inline-flex;
border: 1px solid beige;
margin: -1px 0;
width: 30px;
height: 30px;
} */
.gridColumn {
flex: 1;
border: 1px solid beige;
}
.gridRow {
display: flex;
flex: 1;
}
.default {
background: beige;
}
#button-container {
margin: 3px;
}
#clear-button {
margin: 2px;
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>DOM Manipulation and Events</title>
<script src="javascript.js" defer></script>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1 class="header"> Let's sketch ! </h1>
<div id="setGridSize">
<p id="header-title"> Grid Size :</p>
<input type="text" placeholder="Size of Board" class="size-box">
<span id = "duplicateOfInput"></span>
<button id="submit" > Submit </button>
</div>
<p id="guide"> Enter a number between 2 to 99 </p>
<div class="canvas">
<div class="container"></div>
</div>
<div class="buttons">
<form id="button-container">
<input type="radio" id="blue" name="pen" value="blue-pen"><label for = "blue-pen"> Blue </label>
<input type="radio" id="eraser" name="pen" value="eraser"><label for = "eraser" > Eraser </label>
<input type="radio" id="black" name="pen" value="black-pen"> <label for = "black" > Black </label>
<input type="radio"id="rainbow" name="pen" value="black-pen"> <label for = "rainbow" > Rainbow </label>
</form>
</div>
<button id = "clear-button" > Clear </button>
</body>
</html>
You can use let inputFromBox = document.getElementById('size-box'); and with let number = inputFromBox.value; you can get the value within the click function.
CodePen
You're using document.getElementsByClassName, which is most likely returning an array. Try using inputFromBox[0].value or switching to finding it by an ID.
You may find it easier to use CSS Grid. It allows you to minimise the amount of code you write because you don't have to create rows and columns separately.
Additionally if you set up some CSS variables you can hook the value from the input directly into the stylesheet to update the dimensions of the grid.
// Cache the elements
const grid = document.querySelector('.grid');
const submit = document.querySelector('.submit');
const input = document.querySelector('.size');
// When the button is clicked call `createGrid`
submit.addEventListener('click', createGrid);
function createGrid() {
// Get the value from the input
const { value } = input;
// Array to hold the box strings
const boxes = [];
// Loop to create a grid of boxes - for each
// box push it into the array
for (let i = 1; i <= value * value; i++) {
boxes.push(`<div class="box">${i}</div>`);
}
// `join` the array and update the innerHTML
// of the grid element
grid.innerHTML = boxes.join('');
// Pass the value directly into the spreadsheet.
// This changes the default `--grid-dimension` to the new value
document.documentElement.style.setProperty('--grid-dimension', value);
}
:root { --box-width: 30px; --grid-dimension: 13; }
.grid { margin-top: 1em; display: grid; grid-template-columns: repeat(var(--grid-dimension), var(--box-width)); gap: 0.2em; }
.box { display: flex; justify-content: center; align-items: center; height: var(--box-width); width: var(--box-width); background-color: lightgreen; }
.box:hover { background-color: lightblue; cursor: pointer; }
<input type="text" placeholder="Size of grid" class="size">
<button type="button" class="submit">Create grid</button>
<div class="grid"></div>
whole code
With Javascript I want to remove all current Elements on the Screen exept the text and it's CSS styles. My end goal is that I can essentially exchange the text "Bubble" with "Bounce" and still have the same CSS styling in the end. But as I also need to remove ALL Elements from the screen to run the next code I need to clear out the body and CSS entirely. This leads to my Problem. I dont know how to either get the same CSS styling back after clearing it out nor how to exclude the CSS Styling from the clearing. Can anybody help?
document.getElementById("text").innerHTML = "Bubble";
document.addEventListener("click", next);
function next() {
document.head.innerHTML = " ";
document.getElementById("text").innerHTML = "Bounce";
}
section {
width: 100%;
height: 100vh;
overflow: hidden;
background: #1F69FA;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
content {
min-width: 100%;
max-width: 100%;
margin-left: auto;
margin-right: auto;
text-align: center;
position: absolute;
left: 0;
right: 0
}
section h2 {
font-size: 10em;
color: #333;
margin: 0 auto;
text-align: center;
font-family: consolas;
}
<section>
<div class="content">
<h2 id="text"></h2>
</div>
</section>
If you really need to call document.head.innerHTML = " "; this is one way to do it :
I created a function called add_css() which adds the CSS (which is now stored in a variable) in a style tag in the head of document.
Also your CSS had a typo (content instead of .content)
document.getElementById("text").innerHTML = "Bubble";
const css_to_keep = `section {
width: 100%;
height: 100vh;
overflow: hidden;
background: #1F69FA;
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
}
.content {
min-width: 100%;
max-width: 100%;
margin-left: auto;
margin-right: auto;
text-align: center;
position: absolute;
left: 0;
right: 0
}
section h2 {
font-size: 10em;
color: #333;
margin: 0 auto;
text-align: center;
font-family: consolas;
}`;
document.addEventListener("click", next);
add_css();
function next() {
document.head.innerHTML = " ";
add_css();
document.getElementById("text").innerHTML = "Bounce";
}
function add_css(){
const style_elem = document.createElement('style');
document.head.appendChild(style_elem);
style_elem.type = 'text/css';
style_elem.appendChild(document.createTextNode(css_to_keep));
}
<section>
<div class="content">
<h2 id="text"></h2>
</div>
</section>
You don't need to "remove" anything - just replace the innerHTML of the document body with a new updated section.
// A function that returns a string
// (See template strings below)
function createSection(text) {
return `
<section>
<div class="content">
<h2 id="text">${text}</h2>
</div>
</section>
`;
}
document.body.innerHTML = createSection('Bubble');
document.addEventListener('click', next);
// Replace the body HTML with the new section
function next() {
document.body.innerHTML = createSection('Bounce');
}
section{width:100%;height:100vh;overflow:hidden;background:#1f69fa;display:flex;justify-content:center;align-items:center;flex-direction:column}content{min-width:100%;max-width:100%;margin-left:auto;margin-right:auto;text-align:center;position:absolute;left:0;right:0}section h2{font-size:10em;color:#333;margin:0 auto;text-align:center;font-family:consolas}
Additional documentation
Template/string literals
The Problem
I'm creating a treasure hunt web app that allows you to dynamically add and remove point from the hunt. I do this through the .createElement() and .remove() methods respectively.
When all points have been configured, I grab all the elements (each node is created with a custom web component) with a querySelectorAll(), iterate through them, grab all the info (title, location, clue etc.) and create an object for each point, which is then put in an array. However, if I remove a node before or after I try to save, the deleted element is not removed from the list returned by querySelectorAll(). It throws the error:
Uncaught TypeError: markers[i].shadowRoot.querySelector(...) is null
when reaching the point of any deleted points.
Method for web component removal
// Deletes point marker
deletePoint() {
const delPoint = this.shadowRoot.querySelector(".del-btn");
let pointMarker = delPoint.parentNode.parentNode.parentNode;
pointMarker.remove();
};
Add and save functions
const addPoint = document.querySelector(".add");
const savePoints = document.querySelector(".save");
var data = [];
// Defines markers in preperation for later
let markers = null
// Adds point-marker element to markers div
addPoint.addEventListener("click", () => {
const pointContainer = document.querySelector(".markers");
const node = document.createElement("point-marker");
pointContainer.appendChild(node);
});
// Grabs all point-marker elements, grabs relevant data and adds it to data array
savePoints.addEventListener("click", () => {
// clears data
data = []
markers = document.querySelectorAll("point-marker");
// Iterates through markers
for (i = 0; i < markers.length; i++) {
console.log(`i: ${i}`)
// Grabs all relevant info
let name = markers[i].shadowRoot.querySelector(".name").textContent;
let location = markers[i].shadowRoot.querySelector(".location").textContent;
let clue = markers[i].shadowRoot.querySelector("#clue").value;
// Saves all relevant info in object form
point = {
id: `${i}`,
name: `${name}`,
location: `${location} ${i}`,
clue: `${clue}`
}
// Adds point to data
data.push(point)
}
console.log(data)
});
I'm fairly certain it's an issue with the .remove() method not fully removing the element from the DOM, as it doesn't cause an issue when an element is added, but cannot find another method.
Here's the full code as a snippet if it's of any help:
// === script.js ====
// Declares template variable, containing the html template for the component
const template = document.createElement("template");
template.innerHTML = `
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" integrity="sha384-SZXxX4whJ79/gErwcOYf+zWLeJdY/qpuqC4cAa9rOGUstPomtqpuNWT9wdPEn2fk" crossorigin="anonymous">
<link rel="stylesheet" href="css/style.css">
<style>
#import url('https://fonts.googleapis.com/css2?family=Roboto:wght#400;700&display=swap');
.point-marker {
color: var(--tertiary-color);
background-color: var(--secondary-color);
padding: 2rem;
border-radius: 20px;
margin: 1rem 0;
}
.point-marker h2 {
line-height: 1rem;
}
.point-marker textarea {
width: 100%;
height: 100px;
border-radius: 20px;
resize: vertical;
padding: .5rem;
margin: 1rem 0;
}
.btn {
background-color: var(--primary-color);
border: none;
padding: .5rem 1rem;
min-width: 200px;
color: var(--tertiary-color);
border-radius: 10px;
font-weight: bold;
display: flex;
align-items: center;
justify-content: center;
font-size: medium;
cursor: pointer;
}
.del-btn {
background-color: var(--fail-color);
}
.btns {
display: flex;
width: 100%;
justify-content: space-evenly;
}
.coll-content {
max-height: 0;
overflow: hidden;
transition: max-height 250ms ease-in-out;
}
.collapse-icon {
font-size: large;
}
.const-content {
display: flex;
align-items: center;
justify-content: space-between;
cursor: pointer;
}
</style>
<section class="point-marker">
<div class="const-content">
<h2 class="name">New Point</h2>
<i class="fas fa-minus collapse-icon"></i>
</div>
<div class="coll-content">
<p>Location: <p class="location">location</p></p>
<p>Clue:</p>
<textarea name="clue" id="clue" cols="30" rows="10"></textarea>
<div class="btns">
<button class="btn loc-btn">SET CURRENT LOCATION</button>
<button class="btn del-btn">DELETE POINT</button>
</div>
</div>
</section>
`;
// Declares class PointMarker and casts it as an HTML element
class PointMarker extends HTMLElement {
// Initialises the class every time new object is made
constructor() {
super();
// Declares shadow DOM and sets it to open
this.attachShadow({
mode: "open"
});
this.shadowRoot.appendChild(template.content.cloneNode(true));
setTimeout(() => {
const coll = this.shadowRoot.querySelector(".const-content");
coll.nextElementSibling.style.maxHeight = `${coll.nextElementSibling.scrollHeight}px`;
}, 100)
const name = this.shadowRoot.querySelector(".name")
name.contentEditable = "true";
};
// Collapses or expands the collapsable content
expandCollapse() {
const coll = this.shadowRoot.querySelector(".const-content");
let content = coll.nextElementSibling;
if (content.style.maxHeight) {
content.style.maxHeight = null;
} else {
content.style.maxHeight = `${content.scrollHeight + 30}px`;
};
};
// Deletes point marker
deletePoint() {
this.disconnectedCallback();
const delPoint = this.shadowRoot.querySelector(".del-btn");
let pointMarker = delPoint.parentNode.parentNode.parentNode;
pointMarker.remove();
pointMarker = null;
};
// Adds event listener on all elements with class of const-content or del-btn
connectedCallback() {
this.shadowRoot.querySelector(".collapse-icon").addEventListener("click", () => this.expandCollapse());
this.shadowRoot.querySelector(".del-btn").addEventListener("click", () => this.deletePoint());
console.log("connectedCallback() called");
console.log(this.isConnected)
};
// Adds event listener on all elements with class of del-btn
disconnectedCallback() {
this.shadowRoot.querySelector(".collapse-icon").removeEventListener("click", () => this.expandCollapse());
this.shadowRoot.querySelector(".del-btn").removeEventListener("click", () => this.deletePoint());
console.log("disconnectedCallback() called");
console.log(this.isConnected)
};
};
// Defines <point-marker>
window.customElements.define("point-marker", PointMarker);
const addPoint = document.querySelector(".add");
const savePoints = document.querySelector(".save");
// Defines markers in preperation for later
// Adds point-marker element to markers div
addPoint.addEventListener("click", () => {
const pointContainer = document.querySelector(".markers");
const node = document.createElement("point-marker");
pointContainer.appendChild(node);
});
// Grabs all point-marker elements, grabs relevant data and adds it to data array
savePoints.addEventListener("click", () => {
// clears data
let data = []
markers = document.querySelectorAll("point-marker");
// Iterates through markers
for (i = 0; i < markers.length; i++) {
// Grabs all relevant info
let name = markers[i].shadowRoot.querySelector(".name").textContent;
let location = markers[i].shadowRoot.querySelector(".location").textContent;
let clue = markers[i].shadowRoot.querySelector("#clue").value;
// Saves all relevant info in object form
let point = {}
point = {
id: `${i}`,
name: `${name}`,
location: `${location} ${i}`,
clue: `${clue}`
}
// Adds point to data
data.push(point)
console.log(data)
}
return data;
});
/* style.css */
#import url('https://fonts.googleapis.com/css2?family=Roboto:wght#400;700&display=swap');
:root {
--primary-color: #FA4D05;
--secondary-color: #333;
--tertiary-color: #fff;
--success-color: #97FD87;
--fail-color: #FF5555;
--bg-color: #E5E5E5;
--font-color: #808080;
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
font-family: 'Roboto', sans-serif;
}
html {
scroll-behavior: smooth;
}
body {
min-height: 100vh;
line-height: 2;
color: var(--primary-color);
}
h1 {
font-size: 36px;
}
h2 {
font-size: 24px;
}
nav {
display: flex;
background-color: var(--secondary-color);
justify-content: space-between;
align-items: center;
height: 65px;
padding-left: 5rem;
/* color: var(--primary-color); */
}
nav ul {
list-style: none;
display: flex;
justify-content: space-evenly;
width: 50%;
}
main {
display: flex;
flex-direction: column;
padding: 2rem;
}
main h1 {
margin-bottom: 1rem;
}
.btn {
background-color: var(--primary-color);
border: none;
padding: .5rem 1rem;
min-width: 200px;
color: var(--tertiary-color);
border-radius: 10px;
font-weight: bold;
display: flex;
align-items: center;
justify-content: center;
font-size: medium;
cursor: pointer;
}
.add-point {
background-color: var(--bg-color);
color: var(--font-color);
margin: 1rem 0;
border-radius: 20px;
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
.save {
background-color: var(--success-color);
}
<!-- index.html -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.15.3/css/all.css" integrity="sha384-SZXxX4whJ79/gErwcOYf+zWLeJdY/qpuqC4cAa9rOGUstPomtqpuNWT9wdPEn2fk" crossorigin="anonymous">
<title>Create A Hunt</title>
</head>
<body>
<header>
<nav>
<h2>HOME</h2>
<ul>
<li>
<h2>HUNT</h2>
</li>
<li>
<h2>CREATE</h2>
</li>
</ul>
</nav>
</header>
<main>
<h1>CREATE A HUNT</h1>
<div class="markers">
</div>
<button class="btn add-point add">
<h2>Add Point +</h2>
</button>
<button class="btn add-point save">
<h2>Save Points</h2>
</button>
</main>
<script src="script.js"></script>
<script src="/components/pointMarker.js"></script>
</body>
</html>
TL;DR
Elements removed with the .remove() method are still picked up by the .querySelectorAll() method, presumably because it does not remove it from the DOM fully.
// Deletes point marker
deletePoint() {
this.disconnectedCallback();
const delPoint = this.shadowRoot.querySelector(".del-btn");
let pointMarker = delPoint.parentNode.parentNode.parentNode;
pointMarker.remove();
pointMarker = null;
};
This does not remove the point marker. It removes the contents of the point marker but the point marker is still there.
// Deletes point marker
deletePoint() {
this.disconnectedCallback();
this.remove();
};
This removes the actual element from the page, and your code then works just fine.
In the box I want it to say Hi, but when you click on the div "hi" it will instead toggle the div with "bye" using opacity. My design is not actually with text but svg paths, so this was the best way to translate what I need help with, without having to much code in the snippet (as the svg is quite a lot of code). However, when I click on "hi" nothing happens. What can I change to fix this?
As I am not very experienced with javascript, I am asking you for help to make this function actually work.
const Fana = document.getElementById("Fana")
Fana.addEventListener("onclick", FanaFunction());
function FanaFunction() {
if (clicked = true) {
document.getElementById("Fana").style.opacity = "0";
document.getElementById("Fana-H").style.opacity = "1";
} else {
document.getElementById("Fana").style.opacity = "1";
document.getElementById("Fana-H").style.opacity = "0";
} else if {
document.getElementById("Fana").style.opacity = "1";
document.getElementById("Fana-H").style.opacity = "0";
}
}
body {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 100vh;
background-color: black;
font-family: sans-serif;
font-size: 2em;
text-transform: capitalize;
}
.box-test {
text-align: center;
border: solid 3px red;
width: 400px;
background-color: white;
}
#Fana {
opacity: 1;
cursor: pointer;
}
#Fana-H {
opacity: 0;
cursor: pointer;
}
<div class="box-test">
<div id="Fana">hi</div>
<div id="Fana-H">bye</div>
</div>
else if must be use befor of else!!! and else if need to () and condation.
when use if must == or === this if (clicked = true) is not true code.
I fixed your code:
const Fana = document.getElementById("Fana")
let clicked = true;
Fana.addEventListener("click", FanaFunction);
function FanaFunction() {
if (clicked ) {
document.getElementById("Fana").style.opacity = "0";
document.getElementById("Fana-H").style.opacity = "1";
clicked =false
} else {
document.getElementById("Fana").style.opacity = "1";
document.getElementById("Fana-H").style.opacity = "0";
clicked=true;
}
}
There were more than one issues with your code. I'm sharing working solution below.
Your code had problem with event assignment, you shouldn't use parenthesis just pass the function.
When you use else if you have to add a condition just like if.
clicked = true is not a condition is an assignment. You should use double (or triple, strict equality) equal operator. Also it wasn't declared anywhere.
let sayingHi = true;
const Fana = document.getElementById("Fana")
Fana.addEventListener("click", FanaFunction);
function FanaFunction() {
if (sayingHi) {
document.getElementById("Fana").style.opacity = "0";
document.getElementById("Fana-H").style.opacity = "1";
} else {
document.getElementById("Fana").style.opacity = "1";
document.getElementById("Fana-H").style.opacity = "0";
}
sayingHi = !sayingHi;
}
body {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 100vh;
background-color: black;
font-family: sans-serif;
font-size: 2em;
text-transform: capitalize;
}
.box-test {
text-align: center;
border: solid 3px red;
width: 400px;
background-color: white;
}
#Fana {
opacity: 1;
cursor: pointer;
}
#Fana-H {
opacity: 0;
cursor: pointer;
}
<div class="box-test">
<div id="Fana">hi</div>
<div id="Fana-H">bye</div>
</div>
Your code has problem in event name. It should be "click" instead of "onclick".
Moreover, when you passing function to event listener, you need to pass as function without calling it. Here, you called FanaFunction() when you passing. That will not pass a Function instead it'll pass only return value of that function. So, you've to pass as FanaFunction.
I think "else" and "else if" part is just a typo.
I attached the code in one format. So, you can see easily with copy paste. Moreover, you need to use some postion css properties to overlap between those two. Currently, I saw that bye is still showing in below of hi as a blank one.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title></title>
<style>
body {
display: flex;
justify-content: center;
align-items: center;
flex-direction: column;
height: 100vh;
background-color: black;
font-family: sans-serif;
font-size: 2em;
text-transform: capitalize;
}
.box-test {
text-align: center;
border: solid 3px red;
width: 400px;
background-color: white;
}
#Fana {
opacity: 1;
cursor: pointer;
}
#Fana-H {
opacity: 0;
cursor: pointer;
}
</style>
</head>
<body>
<div class="box-test">
<div id="Fana">hi</div>
<div id="Fana-H">bye</div>
</div>
<script type="text/javascript">
const Fana = document.getElementById("Fana")
Fana.addEventListener("click", FanaFunction);
function FanaFunction() {
if (clicked = true) {
document.getElementById("Fana").style.opacity = "0";
document.getElementById("Fana-H").style.opacity = "1";
} else {
document.getElementById("Fana").style.opacity = "1";
document.getElementById("Fana-H").style.opacity = "0";
}
}
</script>
</body>
</html>
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