I am trying to remove a note from local storage by identifying its
title. I checked w3schools and this forum for info. I am able to save
the array but, I can't remove a specific note.
I tried, no change, an example of what I am trying to achieve,
This is my local storage before removing:
[{title: "Laundry", content: "Fold Clothes"}, {title: "Cook", content:
"Buy Food"}, {title: "Read", content: "Go to the library"}] 0: {title:
"Laundry", content: "Fold Clothes"} 1: {title: "Cook", content: "Buy
Food"} 2: {title: "Read", content: "Go to the library"}
My desired output after removing:
[{title: "Laundry", content: "Fold Clothes"}, {title: "Cook", content:
"Buy Food"}] 0: {title: "Laundry", content: "Fold Clothes"} 1: {title:
"Cook", content: "Buy Food"}
I want to be able to remove an item based on its title Read
const editNote = (e) => {
saveContent.addEventListener('click', (e) => {
e.preventDefault()
let notes = []
let note = {
title: noteTitle.value,
content: noteContent.value
}
// Parse the serialized data back into an aray of objects
notes = JSON.parse(localStorage.getItem('items')) || [];
// Push the new data (whether it be an object or anything else) onto the array
notes.push(note);
// Re-serialize the array back into a string and store it in localStorage
localStorage.setItem('items', JSON.stringify(notes));
// input.textContent = note.title
//remove notes by id
const removeNote = () => {
let title = noteTitle
const index = notes.findIndex((note) => note.title === title)
if (index > -1) {
notes.splice(index,1);
}
}
delNote.addEventListener('click', (e) => {
removeNote()
e.preventDefault()
// window.location.href='index.html'
})
})
}
editNote()
You need to set item into local storage after you update your data
const removeNote = () => {
let title = noteTitle
const index = notes.findIndex((note) => note.title === title)
if (index > -1) {
notes.splice(index,1);
localStorage.setItem('items', JSON.stringify(notes))
}
}
localStorage.removeItem('ITEM TO REMOVE');
Reference: https://developer.mozilla.org/en-US/docs/Web/API/Storage/removeItem
I eventually figured it out. Thank you all for replying and providing guidelines.
let input = document.querySelector('.input-bar')
let addItem = document.querySelector('.submit-btn')
let clearAll = document.querySelector('.clear-btn')
// pay attension to indentation and ele location it will determine success
addItem.addEventListener('click', (e) => {
e.preventDefault()
// Parse the serialized data back into an aray of objects
items = JSON.parse(localStorage.getItem('items')) || [];
// Push the new data (whether it be an object or anything else) onto the array
items.push(input.value);
item = input.value
// Re-serialize the array back into a string and store it in localStorage
localStorage.setItem('items', JSON.stringify(items));
var clear = document.createElement('button')
clear.innerHTML= '<i class="fa fa-trash" style="font-size:20px ;color: #ac2412"></i>'
let itemsEl = document.getElementById('items')
let para = document.createElement("P");
var t = document.createTextNode(`${input.value}`);
para.appendChild(t);
para.appendChild(clear)
itemsEl.appendChild(para);
input.value = ''
clear.addEventListener('click', (e) => {
itemsEl.removeChild(para)
e.preventDefault()
for (let index = 0; index < items.length; index++) {
if (items[index] === para.textContent) {
items.splice(index, 1)
localStorage.setItem('items', JSON.stringify(items));
}
}
})
})
clearAll.addEventListener('click', (e) => {
document.getElementById('items').innerHTML = ''
localStorage.clear()
})
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
color: white;
background-color: black;
margin: 40px 0px;
text-align: center;
}
input {
width: 300px;
height: 46px;
outline: none;
background: transparent;
border-color: silver;
border-radius: 0;
color: var(--mainWhite);
font-size: 1.7rem;
}
h1 {
margin: 20px 0px;
}
.submit-btn {
margin: 0px 5px;
width: 50px;
height: 50px;
outline: none;
/* color: white; */
background-color: rgb(21, 96, 194);
color: white;
font-size: 1.7rem;
}
.items-list {
list-style-type: none;
}
li {
display: inline-flex;
border: 1px solid slategrey;
font-size: 22px;
margin: 20px 0px 0px 0px;
}
button {
outline: none;
margin: 0px 0px 0px 200px;
}
.clear-btn {
width: 100px;
height: 40px;
margin: 30px;
outline: none;
background-color: rgb(21, 96, 194);
color: white;
font-size: 20px;
}
<!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="style.css">
<script src="https://code.jquery.com/jquery-3.2.1.slim.min.js" integrity="sha384-KJ3o2DKtIkvYIK3UENzmM7KCkRr/rE9/Qpg6aAZGJwFDMVNA/GpGFF93hXpG5KkN" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.12.9/umd/popper.min.js" integrity="sha384-ApNbgh9B+Y1QKtv3Rn7W3mgPxhU9K/ScQsAP7hUibX39j7fakFPskvXusvfa0b4Q" crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
<title>Groceries</title>
</head>
<body>
<h1>Grocery List</h1>
<div>
<input class="input-bar" type="text">
<span>
<button class="submit-btn">
<i class="fa fa-pencil" aria-hidden="true"></i>
</button>
</span>
<ul class="items-list" id="items"></ul>
</div>
<button class="clear-btn">Clear</button>
<script src="index.js"></script>
</body>
</html>
Related
I'm trying to figure out how to make a dialogue system that shows the text and after you click it removes all the text in the box and new text appears in its place. (I want to be able to do this multiple times)
var container = document.querySelector(".text");
var speeds = {
pause: 400,
slow: 120,
normal: 50,
fast: 20,
superFast: 10
};
var textLines = [{
speed: speeds.slow,
string: "this is a test"
},
{
speed: speeds.pause,
string: "",
pause: true
},
{
speed: speeds.normal,
string: "pls help me"
},
{
speed: speeds.fast,
string: "idk what im doing",
classes: ["red"]
},
{
speed: speeds.normal,
string: ":("
}
];
var characters = [];
textLines.forEach((line, index) => {
if (index < textLines.length - 1) {
line.string += " ";
}
line.string.split("").forEach((character) => {
var span = document.createElement("span");
span.textContent = character;
container.appendChild(span);
characters.push({
span: span,
isSpace: character === " " && !line.pause,
delayAfter: line.speed,
classes: line.classes || []
});
});
});
function revealOneCharacter(list) {
var next = list.splice(0, 1)[0];
next.span.classList.add("revealed");
next.classes.forEach((c) => {
next.span.classList.add(c);
});
var delay = next.isSpace && !next.pause ? 0 : next.delayAfter;
if (list.length > 0) {
setTimeout(function() {
revealOneCharacter(list);
}, delay);
}
}
setTimeout(() => {
revealOneCharacter(characters);
}, 600)
const btn = document.getElementById('btn');
html,
body {
height: 100%;
width: 100%;
}
.text span {
opacity: 0;
}
.text span.revealed {
opacity: 1;
}
.text span.green {
color: #27ae60;
}
.text span.red {
color: #ff0000;
}
body {
background: #3498db;
padding: 3em;
font-family: 'Sora', monospace;
}
.text {
font-size: 6vw;
word-spacing: 0.2em;
margin: 0 auto;
background: #fff;
padding: 1em;
border-bottom: 1vw solid #0e6dad;
position: relative;
line-height: 1.2em;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>replit</title>
<link href="style.css" rel="stylesheet" type="text/css" />
</head>
<body>
<div class="text">
</div>
<button id="textchanger"> continue </button>
<script src="script.js">
}
</script>
<script src="https://replit.com/public/js/replit-badge.js" theme="blue" defer></script>
</body>
</html>
so far all I'm able to make from this is a single phrase appear on the screen and that's about it. to change it, I have to go in manually.
I make (almost) all the js from scratch because it would have been really hard to refactor your code in order to achieve what you want, what I've done seems to work, it is pretty straightforward :
const container = document.querySelector(".text");
const btn = document.querySelector("#textchanger");
// rename speeds in delays which is more coherant
const delays = {
slow: 120,
normal: 50,
fast: 20,
superFast: 10
};
const textLines = [
{
delay: delays.slow,
string: "this is a test"
},
{
delay: delays.normal,
string: "pls help me"
},
{
delay: delays.fast,
string: "idk what im doing",
classes: ["red"]
},
{
delay: delays.normal,
string: ":("
}
];
const revealLine = (lineIndex = 0) => {
const line = textLines[lineIndex]
let charIndex = 0
const nextChar = () => {
const char = line.string[charIndex]
const span = document.createElement('span')
span.textContent = char
span.classList.add(...(line.classes ?? []))
container.appendChild(span)
charIndex++
if (charIndex < line.string.length)
setTimeout(nextChar, line.delay);
else if (lineIndex + 1 < textLines.length) {
const cb = () => {
// remove this listener to display the next one
btn.removeEventListener('click', cb)
// clear the container
Array.from(container.children).forEach(el => el.remove())
// reveal the next line
revealLine(lineIndex + 1)
}
btn.addEventListener('click', cb)
}
}
nextChar()
}
revealLine()
html,
body {
height: 100%;
width: 100%;
}
.text span.green {
color: #27ae60;
}
.text span.red {
color: #ff0000;
}
body {
background: #3498db;
padding: 3em;
font-family: 'Sora', monospace;
}
.text {
font-size: 6vw;
word-spacing: 0.2em;
margin: 0 auto;
background: #fff;
padding: 1em;
border-bottom: 1vw solid #0e6dad;
position: relative;
line-height: 1.2em;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
</head>
<body>
<div class="text">
</div>
<button id="textchanger"> continue </button>
</body>
</html>
I am pretty new to js, and I am building a color scheme generator as a solo project.
I am now stuck on select the html element that created from dynamically.
I tried to select both label and input element below, using document.getElementByClassName but it gives me 'undefined'
I wanna select both label and input elements and add an click eventListner so that they can copy the result color code from that elements.
<label for='${resultColor}' class='copy-label'>Click to copy!</label>
<input class='result-code' id='${resultColor}' type="text" value='${resultColor}'/>`
const colorPickerModes = [ 'monochrome', 'monochrome-dark', 'monochrome-light', 'analogic', 'complement', 'analogic-complement', 'triad quad']
const colorPickerForm = document.getElementById("colorPick-form");
const colorPickerInput = document.getElementById("colorPicker");
const colorPickerModeDropDown = document.getElementById("colorPick-mode");
const resultColorDiv = document.getElementById("result-color-div");
const resultColorCodeDiv = document.getElementById("result-code-div");
let colorPicked = "";
let modePicked = "";
let resultColorDivHtml =''
let resultCodeDivHtml=''
let colorSchemeSetStrings = [];
let resultColorSchemeSet = [];
fetchToRender()
renderDropDownList();
//listen when user change the color input and save that data in global variable
colorPickerInput.addEventListener(
"change",
(event) => {
//to remove # from the color hex code data we got from the user
colorPicked = event.target.value.slice(1, 7);
},
false
);
//listen when user change the scheme mode dropdownlist value and save that data in global variable
colorPickerModeDropDown.addEventListener('change', (event)=>{
modePicked =
colorPickerModeDropDown.options[colorPickerModeDropDown.selectedIndex].text;
})
//whe user click submit btn get data from user's input
colorPickerForm.addEventListener("submit", (event) => {
event.preventDefault();
// To get options in dropdown list
modePicked =
colorPickerModeDropDown.options[colorPickerModeDropDown.selectedIndex].text;
fetchToRender()
});
//when first load, and when user request a new set of color scheme
function fetchToRender(){
if (!colorPicked) {
//initialize the color and mode value if user is not selected anything
colorPicked = colorPickerInput.value.slice(1, 7);
modePicked = colorPickerModes[0]
}
fetch(
`https://www.thecolorapi.com/scheme?hex=${colorPicked}&mode=${modePicked}`
)
.then((res) => res.json())
.then((data) => {
let colorSchemeSetArray = data.colors;
for (let i = 0; i < 5; i++) {
colorSchemeSetStrings.push(colorSchemeSetArray[i]);
}
// to store each object's hex value
for (let i = 0; i < colorSchemeSetStrings.length; i++) {
resultColorSchemeSet.push(colorSchemeSetStrings[i].hex.value);
}
renderColor();
colorSchemeSetStrings = []
resultColorSchemeSet = [];
});
}
function renderColor(){
//to store result of color scheme set object
resultColorDivHtml = resultColorSchemeSet.map((resultColorItem) => {
return `<div class="result-color"
style="background-color: ${resultColorItem};"></div>`;
}).join('')
resultCodeDivHtml = resultColorSchemeSet
.map((resultColor) => {
return `
<label for='${resultColor}' class='copy-label'>
Click to copy!</label>
<input class='result-code' id='${resultColor}'
type="text" value='${resultColor}'/>`;
})
.join("");
resultColorDiv.innerHTML = resultColorDivHtml;
resultColorCodeDiv.innerHTML = resultCodeDivHtml;
}
function renderDropDownList() {
const colorPickerModeOptionsHtml = colorPickerModes
.map((colorPickerMode) => {
return `<option class='colorSchemeOptions' value="#">${colorPickerMode}</option>`;
})
.join("");
colorPickerModeDropDown.innerHTML = colorPickerModeOptionsHtml;
}
* {
box-sizing: border-box;
}
body {
font-size: 1.1rem;
font-family: "Ubuntu", sans-serif;
text-align: center;
margin: 0;
}
/*------Layout------*/
#container {
margin: 0 auto;
width: 80%;
}
#form-div {
width: 100%;
height:10vh;
margin: 0 auto;
}
#colorPick-form {
display: flex;
width: 100%;
height:6vh;
justify-content: space-between;
}
#colorPick-form > * {
margin: 1rem;
height: inherit;
border: 1px lightgray solid;
font-family: "Ubuntu", sans-serif;
}
#colorPick-form > #colorPicker {
width: 14%;
height: inherit;
}
#colorPick-form > #colorPick-mode {
width: 45%;
padding-left: 0.5rem;
}
#colorPick-form > #btn-getNewScheme {
width: 26%;
}
#main {
display: flex;
flex-direction:column;
width:100%;
margin: .8em auto 0;
height: 75vh;
border:lightgray 1px solid;
}
#result-color-div {
width:100%;
height:90%;
display:flex;
}
#result-color-div > *{
width:calc(100%/5);
}
#result-code-div {
width:100%;
height:10%;
display:flex;
}
.copy-label{
width:10%;
display:flex;
padding:0.5em;
font-size:0.8rem;
align-items: center;
cursor: pointer;
background-color: #4CAF50;
color: white;
}
#result-code-div .result-code{
width:calc(90%/5);
text-align: center;
border:none;
cursor: pointer;
}
.result-code:hover, .result-code:focus, .copy-label:hover, .copy-label:focus{
font-weight:700;
}
/*------Button------*/
#btn-getNewScheme {
background-image: linear-gradient(
to right,
#614385 0%,
#516395 51%,
#614385 100%
);
}
#btn-getNewScheme {
padding:0.8rem 1.5rem;
transition: 0.5s;
font-weight: 700;
background-size: 200% auto;
color: white;
box-shadow: 0 0 20px #eee;
border-radius: 5px;
display: block;
cursor: pointer;
}
#btn-getNewScheme:hover,
#btn-getNewScheme:focus {
background-position: right center; /* change the direction of the change here */
color: #fff;
text-decoration: none;
}
}
<!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="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Ubuntu:wght#300;400;700&display=swap" rel="stylesheet">
<link rel="stylesheet" href="index.css">
<title>Color Scheme Generator</title>
</head>
<body>
<div id="container">
<div>
<header><h1 class="site-title">🦎 Color Scheme Generator 🦎</h1></header>
</div>
<div id="form-div">
<form id="colorPick-form" method="get" >
<input id="colorPicker" type="color" />
<select name="colorPick-mode" id="colorPick-mode">
</select>
<button type='submit' id="btn-getNewScheme">Get Color Scheme</button>
</form>
</div>
<div id="main">
<div id="result-color-div">
</div>
<div id="result-code-div">
</div>
</div>
<script src="index.js" type="module"></script>
</body>
</html>
I think the problem is rendering timing. So you need to add event listener below the code where set innerHTML.
function renderColor() {
// to store result of color scheme set object
resultColorDivHtml = resultColorSchemeSet
.map((resultColorItem) => {
return `<div class="result-color" style="background-color: ${resultColorItem};"></div>`;
})
.join("");
resultCodeDivHtml = resultColorSchemeSet
.map((resultColor) => {
return `
<label for='${resultColor}' class='copy-label'>Click to copy!</label>
<input class='result-code' id='${resultColor}' type="text" value='${resultColor}'/>
`;
})
.join("");
resultColorDiv.innerHTML = resultColorDivHtml;
resultColorCodeDiv.innerHTML = resultCodeDivHtml;
// here! add event listener
const labels = document.getElementsByClassName("result-code");
Object.entries(labels).forEach(([key, label]) => {
label.addEventListener("click", (event) =>
alert(`copy color: ${event.target.value}`)
);
});
}
const resultColorCodeDiv=document.getElementById("resultColorCodeDiv")
const resultColorDiv=document.getElementById("resultColorDiv")
resultColorSchemeSet=[
{color:"red", code: "#ff0000"},
{color:"green", code: "#00ff00"},
{color:"blue", code: "#0000ff"}]
function renderColor(){
//to store result of color scheme set object
resultColorDivHtml = resultColorSchemeSet.map((resultColorItem) => {
return `<div class="result-color" style="background-color: ${resultColorItem.color};"></div>`
}).join('')
resultCodeDivHtml = resultColorSchemeSet
.map((resultColor) => {
return `
<label for='${resultColor.code}' class='copy-label'>Click to copy!</label>
<input class='result-code' id='${resultColor.code}' type="text" value='${resultColor.code}'/>`
})
.join("")
resultColorDiv.innerHTML = resultColorDivHtml
resultColorCodeDiv.innerHTML = resultCodeDivHtml
addListener(document.querySelectorAll(".result-color"))
addListener(document.querySelectorAll(".result-code"))
}
renderColor()
function addListener(elements){
for(const element of elements){
element.addEventListener("click" , ()=>{
// add copy logic here
console.log("hello")
})
}
}
<body>
<div id="resultColorDiv"></div>
<div id="resultColorCodeDiv"></div>
</body>
I am new to development. There of course are a few fundamentals I am struggling with. If anyone could help me and give a little explanation I would greatly appreciate it.
I am creating a synth using the tone.js library. I understand how to create the synth passing it one "Instrument", but I am having an issue doing it dynamically and I am digging myself a hole.
Here's the code:
//instruments
const synth = new Tone.Synth().toDestination();
const amSynth = new Tone.AMSynth().toDestination();
const duoSynth = new Tone.DuoSynth().toDestination();
const fmSynth = new Tone.FMSynth().toDestination();
const membraneSynth = new Tone.MembraneSynth().toDestination();
const metalSynth = new Tone.MetalSynth().toDestination();
const monoSynth = new Tone.MonoSynth({
oscillator: {
type: "square"
},
envelope: {
attack: 0.1
}
}).toDestination();
const noiseSynth = new Tone.NoiseSynth().toDestination();
const pluckSynth = new Tone.PluckSynth().toDestination();
const polySynth = new Tone.PolySynth().toDestination();
const sampler = new Tone.Sampler({
urls: {
A1: "A1.mp3",
A2: "A2.mp3",
},
baseUrl: "https://tonejs.github.io/audio/casio/",
onload: () => {
sampler.triggerAttackRelease(["C1", "E1", "G1", "B1"], 0.5);
}
}).toDestination();
//effects
const distortion = new Tone.Distortion(0.4).toDestination();
const vibrato = new Tone.Vibrato(0.4).toDestination();
const pingPong = new Tone.PingPongDelay("4n", 0.2).toDestination()
const autoWah = new Tone.AutoWah(50, 6, -30).toDestination();
const cheby = new Tone.Chebyshev(50).toDestination();
const autoFilter = new Tone.AutoFilter("4n").toDestination()
const autoPanner = new Tone.AutoPanner("4n").toDestination();
const crusher = new Tone.BitCrusher(4).toDestination();
const chorus = new Tone.Chorus(4, 2.5, 0.5).toDestination();
const feedbackDelay = new Tone.FeedbackDelay("8n", 0.5).toDestination();
const freeverb = new Tone.Freeverb().toDestination();
freeverb.dampening = 1000;
const shift = new Tone.FrequencyShifter(42).toDestination();
const reverb = new Tone.JCReverb(0.4).toDestination();
const phaser = new Tone.Phaser({
frequency: 15,
octaves: 5,
baseFrequency: 1000
}).toDestination();
const tremolo = new Tone.Tremolo(9, 0.75).toDestination();
//array of notes --- we add the sharps in the function
var notes = ['C', 'D', 'E', 'F', 'G', 'A', 'B']
var html = '';
for (var octave = 0; octave < 2; octave++) {
for (var i = 0; i < notes.length; i++) {
var hasSharp = true;
var note = notes[i]
if (note == 'E' || note == 'B')
hasSharp = false;
//white keys with one octive
html += `<div class='whitenote play' onmousedown='noteDown(this)' data-note='${note + (octave + 4)}'>`;
//black keys with one octive
if (hasSharp) {
html += `<div class='blacknote play' onmousedown='noteDown(this)' data-note='${note + '#' + (octave + 4)}'></div>`;
}
html += '</div>'
}
}
$('container').innerHTML = html;
$(".play").click(function(elem) {
var note = elem.dataset.note;
var synth = getSynth(elem.data("synth"));
synth.connect(phaser);
synth.connect(autoWah);
synth.triggerAttackRelease(note, "16n");
event.stopPropagation();
});
function getSynth(name) {
switch (name) {
case "Synth":
return synth;
case "AM":
return amSynth;
case "Duo":
return duoSynth;
case "FM":
return fmSynth;
case "Membrane":
return membraneSynth;
case "Metal":
return metalSynth;
case "Mono":
return monoSynth;
case "Noise":
return noiseSynth;
case "Pluck":
return pluckSynth;
case "Poly":
return polySynth;
}
}
#container {
position: absolute;
height: 200px;
border: 2px solid black;
left: 50%;
top: 50%;
transform: translate(-50%, -50%);
white-space: nowrap;
display: block;
white-space: inherit;
overflow: hidden;
}
.whitenote {
height: 100%;
width: 50px;
background: white;
float: left;
border-right: 1px solid black;
position: relative;
}
.blacknote {
position: absolute;
height: 65%;
width: 55%;
z-index: 1;
background: #777;
left: 68%;
}
.instrument-button {
background: orangered;
border: none;
color: white;
padding: 8px 16px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 12px;
}
.effect-button {
background: blue;
border: none;
color: white;
padding: 8px 16px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 12px;
}
.effect-button-padding {
padding-top: 16px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.26/Tone.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.26/Tone.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src='node_modules\tone\build\Tone.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.26/Tone.js.map'></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
</head>
<body style="align-items: center;">
<div>
<h1>Synth AF</h1>
</div>
<div>
<h4>Intruments</h4>
<button class="btn instrument-button" data-synth="Synth" id="synth-button">Synth</button>
<button class="btn instrument-button" data-synth="AM" id="amSynth-button">AM</button>
<button class="btn instrument-button" data-synth="Duo" id="duoSynth-button">Duo</button>
<button class="btn instrument-button" data-synth="FM" id="fmSynth-button">FM</button>
<button class="btn instrument-button" data-synth="Membrane" id="membraneSynth-button">Drums</button>
<button class="btn instrument-button" data-synth="Metal" id="metalSynth-button">Metal</button>
<button class="btn instrument-button" data-synth="Mono" id="monoSynth-button">Mono</button>
<button class="btn instrument-button" data-synth="Noise" id="noiseSynth-button">Noise</button>
<button class="btn instrument-button" data-synth="Pluck" id="pluckSynth-button">Plucky</button>
<button class="btn instrument-button" data-synth="Poly" id="polySynth-button">Poly</button>
</div>
<div class="effect-button-padding">
<h4>Effects</h4>
<button class='btn effect-button' id="distortion-button">Distortion</button>
<button class='btn effect-button' id="vibrato-button">Vibrato</button>
<button class='btn effect-button' id="pingPong-button">PingPong</button>
<button class='btn effect-button' id="autoWah-button">Wah</button>
<button class='btn effect-button' id="crusher-button">BitCrusher</button>
<button class='btn effect-button' id="phaser-button">Phaser</button>
<button class='btn effect-button' id="reverb-button">Reverb</button>
<button class='btn effect-button' id="autoFilter-button">Auto Filter</button>
<button class='btn effect-button' id="feedbackDelay-button">Feedback</button>
<button class='btn effect-button' id="cheby-button">Chebyshev</button>
</div>
<div class="" id="container">
</div>
</body>
</html>
Here is the UI. (Haven't designed it yet...don't judge)
UI Photo
The idea is to use one of the new instruments created in the one constants by passing it through a button click, to a switch statement and then to the output. I apologize if I didn't explain anything clearly or used the wrong terminology.
I would very much appreciate your help.
Thank you for reading,
FandopTheNoob
// this will be the "state" of the synthesiser
const synthSetup = {
instrument: "",
effects: [],
}
// this is the list of instruments
const instruments = [{
synth: "Synth",
id: "synth-button",
text: "Synth",
tone: new Tone.Synth().toDestination(),
},
{
synth: "AM",
id: "amSynth-button",
text: "AM",
tone: new Tone.AMSynth().toDestination(),
},
]
// this is the list of effects
const effects = [{
id: "distortion-button",
text: "Distortion",
tone: new Tone.Distortion(0.4).toDestination(),
},
{
id: "vibrator-button",
text: "Vibrato",
tone: new Tone.Vibrato(0.4).toDestination(),
},
]
// setting up the instruments & effects buttons
const instrumentsHtml = (instruments) => {
return instruments.map(({
synth,
id,
text
}) => {
return `
<button class="btn instrument-button" data-synth=${synth} id="${id}">${text}</button>
`
}).join('')
}
const effectsHtml = (effects) => {
return effects.map(({
id,
text
}) => {
return `
<button class="btn effect-button" id="${id}">${text}</button>
`
}).join('')
}
const instrumentsContainer = document.getElementById("btn-group-instruments")
instrumentsContainer.innerHTML = instrumentsHtml(instruments)
const effectsContainer = document.getElementById("btn-group-effects")
effectsContainer.innerHTML = effectsHtml(effects)
// setting up click handlers on the instruments & effects buttons
$("body").on("click", ".instrument-button", function() {
// setting up synthSetup.instrument:
synthSetup.instrument = $(this).data("synth")
})
$("body").on("click", ".effect-button", function() {
// setting up synthSetup.effects:
synthSetup.effects = [...new Set([...synthSetup.effects, $(this).attr("id")])]
})
//array of notes --- we add the sharps in the function
var notes = ['C', 'D', 'E', 'F', 'G', 'A', 'B']
var html = '';
for (var octave = 0; octave < 2; octave++) {
for (var i = 0; i < notes.length; i++) {
var hasSharp = true;
var note = notes[i]
if (note == 'E' || note == 'B')
hasSharp = false;
//white keys with one octave
html += `<div class='whitenote play' data-note='${note + (octave + 4)}'>`;
//black keys with one octave
if (hasSharp) {
html += `<div class='blacknote play' data-note='${note + '#' + (octave + 4)}'></div>`;
}
html += '</div>'
}
}
const container = document.getElementById("container")
container.innerHTML = html;
$("body").on("click", ".play", function() {
if (!synthSetup.instrument) {
alert("Choose an instrument first!")
} else {
const {
tone: synth
} = instruments.find(({
synth
}) => synth === synthSetup.instrument)
const note = $(this).data("note")
// connecting the effects
synthSetup.effects.forEach(e => {
const effect = effects.find(({
id
}) => e)
synth.connect(effect.tone)
})
const now = Tone.now()
synth.triggerAttackRelease(note, "2n", now)
}
})
html,
body {
height: 100%;
position: relative;
}
#container {
position: absolute;
height: 200px;
border: 2px solid black;
left: 50%;
bottom: 0;
transform: translateX(-50%);
white-space: nowrap;
display: block;
white-space: inherit;
overflow: hidden;
}
.whitenote {
height: 100%;
width: 50px;
background: white;
float: left;
border-right: 1px solid black;
position: relative;
}
.blacknote {
position: absolute;
height: 65%;
width: 55%;
z-index: 1;
background: #777;
left: 68%;
}
.instrument-button {
background: orangered;
border: none;
color: white;
padding: 8px 16px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 12px;
}
.effect-button {
background: blue;
border: none;
color: white;
padding: 8px 16px;
text-align: center;
text-decoration: none;
display: inline-block;
font-size: 12px;
}
.effect-button-padding {
padding-top: 16px;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.26/Tone.min.js"></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/tone/14.8.26/Tone.js.map'></script>
<script src="https://code.jquery.com/jquery-3.6.0.js" integrity="sha256-H+K7U5CnXl1h5ywQfKtSj8PCmoN9aaq30gDh27Xc0jk=" crossorigin="anonymous"></script>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css" integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous">
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/js/bootstrap.min.js" integrity="sha384-JZR6Spejh4U02d8jOt6vLEHfe/JQGiRRSQQxSfFWpi1MquVdAyjUar5+76PVCmYl" crossorigin="anonymous"></script>
<div>
<h1>Synth AF</h1>
</div>
<div>
<h4>Intruments</h4>
<div id="btn-group-instruments"></div>
</div>
<div class="effect-button-padding">
<h4>Effects</h4>
<div id="btn-group-effects"></div>
</div>
<div class="" id="container">
</div>
So, here's the next step for this synthesizer:
the current state of the synthesizer is kept in synthSetup
the instruments are stored as an array of objects
the effects are stored as an array of objects
instruments & effects are put to the DOM dynamically
on clicking any white or black button the synthSetup (state) is read & the note is played (chosen instrument & the list of effects)
Issues:
you cannot remove an effect from the list of effects (it could be handled in the click handler of the effect buttons)
A simple multiple choice quiz with one problem I can't solve. At first When I clicked the 'next question' button the next question and answers didn't show only when clicked a second time the next question and answers showed.
When I placed runningQuestion++ above questions[runningQuestion].displayAnswers()
like I did in the nextQuestion function the initial problem is solved but reappears after the last question when you are asked to try again. Only now when you click 'try again' now ofcourse it skips the first question.
class Question {
constructor(question, answers, correct) {
this.question = question;
this.answers = answers;
this.correct = correct;
}
displayAnswers() {
document.querySelector('.question').innerHTML = `<div class="q1">${this.question}</div>`
let i = 0
let answers = this.answers
for (let el of answers) {
let html = `<div class="name" id=${i}>${el}</div>`
document.querySelector('.answers').insertAdjacentHTML('beforeend', html)
i++
}
}
}
const q1 = new Question('What\'s the capitol of Rwanda?', ['A: Dodoma', 'B: Acra', 'C: Kigali'], 2);
const q2 = new Question('What\'s is the square root of 0?', ["A: Not possible", 'B: 0', 'C: 1'], 1);
const q3 = new Question('Who was Rome\'s first emperor?', ['A: Tiberius', 'B: Augustus', 'C: Marcus Aurelius'], 1);
const questions = [q1, q2, q3];
let runningQuestion;
let gamePlaying;
init()
document.querySelector('.button1').addEventListener('click', nextQuestion)
function nextQuestion(e) {
console.log(e.target)
if (gamePlaying === true && runningQuestion <= questions.length - 1) {
clearAnswers()
document.querySelector('.button1').textContent = 'Next Question'
runningQuestion++
questions[runningQuestion].displayAnswers()
}
if (runningQuestion >= questions.length - 1) {
document.querySelector('.button1').textContent = 'Try again!'
runningQuestion = 0
}
}
function clearAnswers() {
document.querySelectorAll('.name').forEach(el => {
el.remove()
})
}
document.querySelector('.button2').addEventListener('click', resetGame)
function resetGame() {
document.querySelector('.button1').textContent = 'Next Question'
clearAnswers()
runningQuestion = 0
questions[runningQuestion].displayAnswers()
}
function init() {
gamePlaying = true;
runningQuestion = 0;
questions[runningQuestion].displayAnswers()
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
.container {
display: flex;
width: 400px;
height: auto;
margin: 100px auto;
align-items: center;
flex-direction: column;
}
.question {
margin-top: 40px;
color: rgb(102, 0, 0);
font-size: 1.4rem;
}
.answers {
display: flex;
flex-direction: column;
margin-top: 10px;
height: 100px;
margin-bottom: 15px;
}
.name {
margin-top: 20px;
cursor: pointer;
color: rgb(102, 0, 0);
font-size: 1.2rem;
}
.button1 {
margin-top: 50px;
border-style: none;
width: 350px;
height: 50px;
font-size: 1.4rem;
}
ul>li {
list-style-type: none;
margin-top: 10px;
font-size: 1.2rem;
color: rgb(102, 0, 0);
height: 30px;
cursor: pointer;
display: block;
}
.button2 {
margin-top: 20px;
border-style: none;
width: 350px;
height: 50px;
font-size: 1.4rem;
}
<!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="styles.css">
<title>Quiz</title>
</head>
<body>
<div class="container">
<div class="question"></div>
<div class="answers"></div>
<button type="button" class="button1">Next Question</button>
<button type="button" class="button2">Reset</button>
</div>
<script src="app.js"></script>
</body>
</html>
The problem with the current version is that you reset runningQuestion to 0, and when clicking on the button, you execute nextQuestion, which, as the name implies, goes to the next question (runningQuestion++).
I see 2 ways of solving this. Either the "easy" way, by resetting runningQuestion to -1 so that it goes to 0:
class Question{constructor(e,s,t){this.question=e,this.answers=s,this.correct=t}displayAnswers(){document.querySelector(".question").innerHTML=`<div class="q1">${this.question}</div>`;let e=0,s=this.answers;for(let t of s){let s=`<div class="name" id=${e}>${t}</div>`;document.querySelector(".answers").insertAdjacentHTML("beforeend",s),e++}}}const q1=new Question("What's the capitol of Rwanda?",["A: Dodoma","B: Acra","C: Kigali"],2),q2=new Question("What's is the square root of 0?",["A: Not possible","B: 0","C: 1"],1),q3=new Question("Who was Rome's first emperor?",["A: Tiberius","B: Augustus","C: Marcus Aurelius"],1),questions=[q1,q2,q3];let runningQuestion,gamePlaying;init(),document.querySelector(".button1").addEventListener("click",nextQuestion);
/* Nothing changed above */
function nextQuestion(e) {
runningQuestion++; // <---------------------------------------------------------
if (gamePlaying === true && runningQuestion <= questions.length - 1) {
clearAnswers();
document.querySelector('.button1').textContent = 'Next Question';
questions[runningQuestion].displayAnswers();
}
if (runningQuestion >= questions.length - 1) {
document.querySelector('.button1').textContent = 'Try again!';
runningQuestion = -1; // <-----------------------------------------------------
}
}
/* Nothing changed below */
function clearAnswers(){document.querySelectorAll(".name").forEach(e=>{e.remove()})}function resetGame(){document.querySelector(".button1").textContent="Next Question",clearAnswers(),runningQuestion=0,questions[runningQuestion].displayAnswers()}function init(){gamePlaying=!0,runningQuestion=0,questions[runningQuestion].displayAnswers()}document.querySelector(".button2").addEventListener("click",resetGame);
/* Same CSS as yours */ *{box-sizing:border-box;margin:0;padding:0}.container{display:flex;width:400px;height:auto;margin:100px auto;align-items:center;flex-direction:column}.question{margin-top:40px;color:#600;font-size:1.4rem}.answers{display:flex;flex-direction:column;margin-top:10px;height:100px;margin-bottom:15px}.name{margin-top:20px;cursor:pointer;color:#600;font-size:1.2rem}.button1{margin-top:50px;border-style:none;width:350px;height:50px;font-size:1.4rem}ul>li{list-style-type:none;margin-top:10px;font-size:1.2rem;color:#600;height:30px;cursor:pointer;display:block}.button2{margin-top:20px;border-style:none;width:350px;height:50px;font-size:1.4rem}
<!-- Same HTML as yours --> <div class="container"> <div class="question"></div><div class="answers"></div><button type="button" class="button1">Next Question</button> <button type="button" class="button2">Reset</button></div>
or another way, which I find cleaner. A problem you can run into with your current code, is that if you have other things to keep track of, like a score, for example, you might forget to reset them as well, inside your nextQuestion function. And if you add other stuff, you'll need to reset them in multiple places in your code.
What I would do is simply reuse the resetGame function to reset everything:
class Question{constructor(e,s,t){this.question=e,this.answers=s,this.correct=t}displayAnswers(){document.querySelector(".question").innerHTML=`<div class="q1">${this.question}</div>`;let e=0,s=this.answers;for(let t of s){let s=`<div class="name" id=${e}>${t}</div>`;document.querySelector(".answers").insertAdjacentHTML("beforeend",s),e++}}}const q1=new Question("What's the capitol of Rwanda?",["A: Dodoma","B: Acra","C: Kigali"],2),q2=new Question("What's is the square root of 0?",["A: Not possible","B: 0","C: 1"],1),q3=new Question("Who was Rome's first emperor?",["A: Tiberius","B: Augustus","C: Marcus Aurelius"],1),questions=[q1,q2,q3];let runningQuestion,gamePlaying;
/* Nothing changed above */
const btn1 = document.querySelector('.button1');
init();
btn1.addEventListener("click", onButtonClick);
function isLastQuestion() { return runningQuestion >= questions.length - 1; }
function onButtonClick() {
if (gamePlaying === true && !isLastQuestion()) {
runningQuestion++;
displayQuestion();
} else {
resetGame();
}
}
function displayQuestion() {
clearAnswers();
btn1.textContent = isLastQuestion() ? 'Try again' : 'Next Question';
questions[runningQuestion].displayAnswers();
}
/* Nothing changed below */
function clearAnswers(){document.querySelectorAll(".name").forEach(e=>{e.remove()})}function resetGame(){document.querySelector(".button1").textContent="Next Question",clearAnswers(),runningQuestion=0,questions[runningQuestion].displayAnswers()}function init(){gamePlaying=!0,runningQuestion=0,questions[runningQuestion].displayAnswers()}document.querySelector(".button2").addEventListener("click",resetGame);function init(){gamePlaying=true;runningQuestion = 0;questions[runningQuestion].displayAnswers()}
/* Same CSS as yours */ *{box-sizing:border-box;margin:0;padding:0}.container{display:flex;width:400px;height:auto;margin:100px auto;align-items:center;flex-direction:column}.question{margin-top:40px;color:#600;font-size:1.4rem}.answers{display:flex;flex-direction:column;margin-top:10px;height:100px;margin-bottom:15px}.name{margin-top:20px;cursor:pointer;color:#600;font-size:1.2rem}.button1{margin-top:50px;border-style:none;width:350px;height:50px;font-size:1.4rem}ul>li{list-style-type:none;margin-top:10px;font-size:1.2rem;color:#600;height:30px;cursor:pointer;display:block}.button2{margin-top:20px;border-style:none;width:350px;height:50px;font-size:1.4rem}
<!-- Same HTML as yours --> <div class="container"> <div class="question"></div><div class="answers"></div><button type="button" class="button1">Next Question</button> <button type="button" class="button2">Reset</button></div>
I'm creating a to-do list app, and in the app there is a div that wraps an input box (for the to-do item and so the user can edit the to-do) and a icon from font-awesome. When the user clicks on the icon, I want the entire div (which contains the to-do and the delete icon) to be deleted. But when tried to do that, it didn't work. Can someone help me?
Here's the JS Code
$(document).ready(() => {
$(".input input").on("keypress", check_todo);
$(".fa-trash").on("click", ".todo_container", delete_todo);
})
// delete todo
let delete_todo = (e) => {
e.target.remove();
}
// add todo
let add_todo = () => {
let todo = $(".input input").val();
$(".output").append(`
<input type="text" placeholder="Edit To-do" value="${todo}"><i class="fa fa-trash fa-lg" aria-hidden="true"></i>
`);
$(".input input").val("");
}
// check todo
let check_todo = (e) => {
if (e.keyCode == 13) {
if ($(".input input").val() == "") {
no_todo();
} else {
add_todo();
}
}
}
// no todo
let no_todo = () => {
alert("Please add a new todo");
}
See the html and a demo
You should binding to .out-put container.
$(".output").on("click",".fa-trash" , delete_todo);
http://codepen.io/Vrety/pen/WoWmaE
http://codepen.io/anon/pen/eBoXZe
In your event listener, you need to swap ".todo_container" and ".fa-trash".
$(".todo_container").on("click",".fa-trash" , delete_todo);
This statement means, when a click event occurs and bubbles up to .todo_container, check if the clicked element is .fa-trash, if so call the function.
Then change your delete function
let delete_todo = (e) => {
$(e.currentTarget).closest('.todo_container').remove()
}
This code means from the clicked icon, travel up the dom to find .todo_container, then remove it.
Good job with using the delegation in JQuery but while using it
$(".todo_container").on("click",".fa-trash" , delete_todo);
The base element $(".todo_container") needs to be static, You are deleting this also in the delete_todo() function.
Try using $(".output") instead and see if it works.
here is a working code
$(document).ready(function() {
$(".input input").on("keypress", check_todo);
//$(".fa-trash").on("click", ".todo_container", delete_todo);
$(".todo_container .fa-trash").on("click", delete_todo);
})
// delete todo
let delete_todo = function(e) {
//e.target.remove();
$(e.target).parent().remove();
}
// add todo
let add_todo = function() {
let todo = $(".input input").val();
//to do container element, the delete icon will added later
var toDoContainer = $(`
<div class="todo_container">
<input type="text" placeholder="Edit To-do" value="${todo}"></div>
`);
//create delete icon and set event listener
var elem = $('<i class="fa fa-trash fa-lg" aria-hidden="true"></i>').on("click", delete_todo).appendTo(toDoContainer);
$(".output").append(toDoContainer);
$(".input input").val("");
}
// check todo
let check_todo = (e) => {
if (e.keyCode == 13) {
if ($(".input input").val() == "") {
no_todo();
} else {
add_todo();
}
}
}
// no todo
let no_todo = () => {
alert("Please add a new todo");
}
#font-face {
font-family: Open Sans;
src: url("assets/fonts/OpenSans-Regular");
font-weight: 400
}
#font-face {
font-family: Open Sans;
src: url("assets/fonts/OpenSans-Semibold");
font-weight: 600
}
* {
margin: 0;
padding: 0;
transition: all 200ms ease-in-out;
}
*::selection {
background-color: #ffffaa;
}
.container {
width: 60%;
margin: 20px auto;
}
.header {
padding: 10px;
}
.header input {
padding: 10px;
width: 60%;
border: none;
outline: none;
font: 400 1.8em Open Sans;
}
.to-do {
padding: 10px;
text-align: center;
}
.input input {
padding: 10px;
width: 40%;
border: none;
outline: none;
font: 600 1em Open Sans;
border-bottom: 3px solid #333;
}
.output {
margin: 10px;
}
.output input {
padding: 20px;
border: none;
outline: none;
font: 600 1em Open Sans;
width: 50%;
cursor: pointer;
}
.output input:hover {
background-color: #eee;
}
.fa-trash {
padding: 20px;
cursor: pointer;
}
.fa-trash:hover {
background-color: #333;
color: #fff;
}
<head>
<title>To-do List</title>
<!-- FONTS -->
<link href="https://fonts.googleapis.com/css?family=Open+Sans:400,500" rel="stylesheet">
</head>
<body>
<div class="container">
<header class="header">
<input type="text" name="edit_name" placeholder="Edit Name">
</header>
<section class="to-do">
<div class="input">
<input type="text" name="add_todo" placeholder="Click To Add A New To-do">
</div>
<div class="output">
<div class="todo_container">
<input type="text" placeholder="Edit To-do" value="Todo #1"><i class="fa fa-trash fa-lg" aria-hidden="true"></i>
</div>
<div class="todo_container">
<input type="text" placeholder="Edit To-do" value="Todo #2"><i class="fa fa-trash fa-lg" aria-hidden="true"></i>
</div>
</div>
</section>
</div>
<!-- JQUERY -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.0/jquery.min.js"></script>
<script src="https://use.fontawesome.com/5840114410.js"></script>
</body>