I am a newbie trying to learn JavaScripts. So I'm trying to clone an app called Momentum, and I am facing a problem with adding and removing the form and name of the user.
as it can be seen in the loadName() function, if there is a name, it should activate greetUser() function to remove the "showing" class from the form and add the "showing" to greeting class list. If there isn't a name, it should display a form where the user can enter their name.
However, even if I assign the name or not, neither the form will display nor the name.
I have tried changing the names, css file, and other things that I could think of but did not work as I expected. Below is the code that I am working with. It probably is some stupid mistake that I've made, but I just am not able to find out what the problem is.
greetings.js
const form = document.querySelector(".js-form");
const input = form.querySelector("input");
const greeting = document.querySelector(".js-greetings");
const USER_LS = "currentUser";
const SHOWING_CN = "showing";
function saveName(text) {
localStorage.setItem(USER_LS, text);
}
function handleSubmit() {
event.preventDefault();
const currentValue = input.value;
greetUser(currentValue);
saveName(currentValue);
}
function askForName() {
form.classList.add(SHOWING_CN);
form.addEventListener("submit", handleSubmit);
}
function greetUser(text) {
form.classList.remove(SHOWING_CN);
greeting.classList.add(SHOWING_CN);
greeting.innerText = `Hello, ${text}`;
}
function loadName() {
const currentUser = localStorage.getItem(USER_LS);
if (currentUser === null) {
askForName();
} else {
greetUser(currentUser);
}
}
function init() {
loadName();
}
index.css
.form,
.greetings {
display: none;
}
.showing {
display: block;
}
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Something</title>
<link rel="stylesheet" href="index.css" />
</head>
<body>
<div class="js-clock">
<h1>00:00</h1>
</div>
<form class="js-form form">
<input type="text" placeholder="What is your name?" />
</form>
<h4 class="js-greetings greetings"></h4>
<script src="clock.js"></script>
<script src="greetings.js"></script>
</body>
</html>
There was an issue with firing off your loadName() function. This was being called from init(), but nothing was calling init(). I changed it to call loadName() once the window has loaded. There was also an issue with getting the constant USER_LS from local storage when it hadn't yet been set. I've just referred directly to it since it is defined globally. I've demonstrated the USER_LS being set to a name as well as to null (this is commented out since a constant can only be defined once) to show how the inputs appear for each scenario:
const form = document.querySelector(".js-form");
const input = form.querySelector("input");
const greeting = document.querySelector(".js-greetings");
// const USER_LS = null;
const USER_LS = "Bob";
const SHOWING_CN = "showing";
function saveName(text) {
localStorage.setItem(USER_LS, text);
}
function handleSubmit() {
event.preventDefault();
const currentValue = input.value;
greetUser(currentValue);
saveName(currentValue);
}
function askForName() {
form.classList.add(SHOWING_CN);
form.addEventListener("submit", handleSubmit);
}
function greetUser(text) {
form.classList.remove(SHOWING_CN);
greeting.classList.add(SHOWING_CN);
greeting.innerText = `Hello, ${text}`;
}
function loadName() {
const currentUser = USER_LS;
if (currentUser === null) {
askForName();
} else {
greetUser(currentUser);
}
}
window.load = loadName();
.form,
.greetings {
display: none;
}
.showing {
display: block;
}
<div class="js-clock">
<h1>00:00</h1>
</div>
<form class="js-form form">
<input type="text" placeholder="What is your name?" />
</form>
<h4 class="js-greetings greetings"></h4>
<script src="clock.js"></script>
<script src="greetings.js"></script>
Related
Here's a simplified example of something I'm trying to do.
I've got an input field which I need to get the value from when the user types in his name and click the "Save changes" button.
What I then need is for the username variable to update accordingly to what the user typed in. The page has localization features which complicate things slightly. I can't seem to populate the updated value within the translations object (anywhere username is mentioned, the initialized value is retained and not the last assigned one). This is the part I'm struggling with.
Here's my code:
var p = document.querySelectorAll("p")[0];
var input = document.querySelectorAll("input")[0];
var button = document.querySelectorAll("button")[0];
var locale = "en";
var username = "";
button.onclick = function() {
username = input.value;
document.querySelectorAll("[data-language-key]").forEach(translate);
}
function translate(element) {
const key = element.getAttribute("data-language-key");
const translation = translations[locale][key];
element.innerText = translation;
}
var translations = {
"en": {
"message": `Good morning, ${username}!`,
},
"fr": {
"message": `Bonjour, ${username} !`,
}
}
body {
background-color: gray;
}
button {
margin: 200px;
}
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title></title>
</head>
<body>
<p data-language-key="message">Good morning, {username}!</p>
<input type="text" placeholder="Type your name...">
<button>Save changes</button>
</body>
</html>
JavaScript beginner here (if you can ELI5 your answer, I'd appreciate greatly!)
As suggested in the comments, the variable is substituted when the literal is read, therefore we postpone the reading until it's actually needed. This is done using a function.
var p = document.querySelector("p");
var input = document.querySelector("input");
var button = document.querySelector("button");
var locale = "en";
var username = "";
button.onclick = function() {
username = input.value;
translate(document.querySelector("[data-language-key]"));
}
function translate(element) {
var key = element.getAttribute("data-language-key")
const translation = translations[locale][key];
var text = translation(username);
element.innerText = text;
}
var translations = {
"en": {
"message": () => `Good morning, ${username}!`,
},
"fr": {
"message": () => `Bonjour, ${username} !`,
}
}
<p data-language-key="message">Good morning, {username}!</p>
<input type="text" placeholder="Type your name...">
<button>Save changes</button>
i hope you guys fine, well..
I'm doing a To Do List, and there is a problem in my code, which I've been trying to solve for a few days, and no effective results was made..
If you guys test in the snippet with me, i am sure, that will be more
clear to understand.
When i click in some list element, my javascript should change or add the className, and add a class call 'selected'.
because, when i will click in the remove button, they will delete all elements with 'selected' classList in the list. (as you can see in the code)
But the className a not being add to the tag in the first click, just works if i click in the element one more time.
i simplified my code, just to show the real problem:
Link to jsfiddle : https://jsfiddle.net/myqrzcs2/
const textoTarefa = document.getElementById('texto-tarefa');
const criarTarefa = document.getElementById('criar-tarefa');
const listaTarefas = document.getElementById('lista-tarefas');
criarTarefa.onclick = function click() {
const lista = document.createElement('li');
lista.className = 'lista';
lista.id = 'lista';
lista.tabIndex = '0';
lista.innerHTML = textoTarefa.value;
listaTarefas.appendChild(lista);
document.body.appendChild(listaTarefas);
textoTarefa.value = '';
};
const completedLine = document.querySelector('ol');
function umClick(event) {
if (event.target.tagName === 'LI') {
const listas = document.querySelectorAll('.lista');
listas.forEach((i) => {
i.addEventListener('click', function semNomeDois() {
listas.forEach((j) => j.classList.remove('selected'));
this.classList.add('selected');
});
});
}
}
completedLine.addEventListener('click', umClick);
function removeSelected() {
// teste
const listaSelected = document.querySelectorAll('.selected');
for (let i = 0; i < listaSelected.length; i += 1) {
listaSelected[i].remove();
}
}
.lista:focus {
background: red;
}
<!DOCTYPE html>
<html>
<head>
<link rel='stylesheet' href='style.css'>
</head>
<body>
<header>
<h1>My List</h1>
</header>
<input id='texto-tarefa' type="text" />
<button id='criar-tarefa' type="submit" onClick='click()'>Add</button>
<ol id='lista-tarefas'>
</ol>
<button id='remover-selecionado' type="submit" onClick='removeSelected()'>Remove Selected (Only One)</button>
<script src="script.js"></script>
</body>
</html>
But how can i make the class be add, just in the first click, not in the second?
I think you got off on the wrong foot in programming this.
Here is the way I use, may it inspire you.
const
textoTarefa = document.getElementById('texto-tarefa')
, criarTarefa = document.getElementById('criar-tarefa')
, removerSelec = document.getElementById('remover-selecionado')
, listaTarefas = document.getElementById('lista-tarefas')
;
var li_selected = null
;
textoTarefa.oninput = () =>
{
criarTarefa.disabled = (textoTarefa.value.trim().length ===0 )
}
criarTarefa.onclick = () =>
{
listaTarefas.appendChild( document.createElement('li')).textContent = textoTarefa.value.trim()
textoTarefa.value = ''
textoTarefa.focus()
criarTarefa.disabled = true
}
listaTarefas.onclick = ({target}) =>
{
if (!target.matches('li')) return
if (!!li_selected && li_selected !== target ) li_selected.classList.remove('listaSelect')
li_selected = target.classList.toggle('listaSelect') ? target : null
removerSelec.disabled = !li_selected
}
removerSelec.onclick = () =>
{
listaTarefas.removeChild(li_selected)
li_selected = null
removerSelec.disabled = true
}
.listaSelect {
background: #ff0000c4;
}
ol#lista-tarefas {
cursor : pointer
}
<input id='texto-tarefa' type="text" value="">
<button id='criar-tarefa' disabled>Add</button>
<button id='remover-selecionado' disabled>Remove Selected</button>
<ol id='lista-tarefas'></ol>
You were unnecessarily adding an event listener to each item in the list.
You can check the updated fiddle here: https://jsfiddle.net/msa9v2nf/
Since you're already checking which target element is clicked, there isn't any need to add an individual listener to each child item in the list.
I updated the umClick function:
function umClick(event) {
if (event.target.tagName === 'LI') {
const listas = document.querySelectorAll('.lista');
listas.forEach((i) => {
listas.forEach((j) => j.classList.remove('selected'));
event.target.classList.add('selected');
});
}
}
The problem is you call the function umClick and call the function to add .selected within a click event in the same function umClick.
What happens is the click event completedLine.addEventListener('click', umClick); happens before the i.addEventListener('click', function semNomeDois() event. This is why you need a first click on the ol tag for only the first time.
To fixes this you have multiple options:
instead of calling click event on ol tag you can call mousedown which happens before click event.
Calling a click event on the li elements on creation, which needs a new function.
Depending on Vektor's answer, you can remove the unnecessary click event inside the first click event.
Also, I've made the red highlight on the .selected class instead of :focus, just to make it clear when the item is selected.
.selected {
background: red;
}
First Solution
const textoTarefa = document.getElementById('texto-tarefa');
const criarTarefa = document.getElementById('criar-tarefa');
const listaTarefas = document.getElementById('lista-tarefas');
criarTarefa.onclick = function click() {
const lista = document.createElement('li');
lista.className = 'lista';
lista.id = 'lista';
lista.tabIndex = '0';
lista.innerHTML = textoTarefa.value;
listaTarefas.appendChild(lista);
document.body.appendChild(listaTarefas);
textoTarefa.value = '';
};
const completedLine = document.querySelector('ol');
function umClick(event) {
if (event.target.tagName === 'LI') {
const listas = document.querySelectorAll('.lista');
listas.forEach((i) => {
i.addEventListener('click', function semNomeDois() {
listas.forEach((j) =>{
if(j != event.target)
j.classList.remove('selected');
});
this.classList.add('selected');
});
});
}
}
completedLine.addEventListener('mousedown', umClick);
function removeSelected() {
// teste
const listaSelected = document.querySelectorAll('.selected');
for (let i = 0; i < listaSelected.length; i += 1) {
listaSelected[i].remove();
}
}
.selected {
background: red;
}
<!DOCTYPE html>
<html>
<head>
<link rel='stylesheet' href='style.css'>
</head>
<body>
<header>
<h1>My List</h1>
</header>
<input id='texto-tarefa' type="text" />
<button id='criar-tarefa' type="submit" onClick='click()'>Add</button>
<ol id='lista-tarefas'>
</ol>
<button id='remover-selecionado' type="submit" onClick='removeSelected()'>Remove Selected (Only One)</button>
<script src="script.js"></script>
</body>
</html>
Second Solution
const textoTarefa = document.getElementById('texto-tarefa');
const criarTarefa = document.getElementById('criar-tarefa');
const listaTarefas = document.getElementById('lista-tarefas');
criarTarefa.onclick = function click() {
const lista = document.createElement('li');
lista.className = 'lista';
lista.id = 'lista';
lista.tabIndex = '0';
lista.innerHTML = textoTarefa.value;
listaTarefas.appendChild(lista);
lista.addEventListener('click',function(){
itemClick(this);
});
document.body.appendChild(listaTarefas);
textoTarefa.value = '';
};
function itemClick(item) {
const listas = document.querySelectorAll('.lista');
listas.forEach((j) =>j.classList.remove('selected'));
item.classList.add('selected');
}
function removeSelected() {
// teste
const listaSelected = document.querySelectorAll('.selected');
for (let i = 0; i < listaSelected.length; i += 1) {
listaSelected[i].remove();
}
}
.selected {
background: red;
}
<!DOCTYPE html>
<html>
<head>
<link rel='stylesheet' href='style.css'>
</head>
<body>
<header>
<h1>My List</h1>
</header>
<input id='texto-tarefa' type="text" />
<button id='criar-tarefa' type="submit" onClick='click()'>Add</button>
<ol id='lista-tarefas'>
</ol>
<button id='remover-selecionado' type="submit" onClick='removeSelected()'>Remove Selected (Only One)</button>
<script src="script.js"></script>
</body>
</html>
I am not fully understand your problem but,
If you want to add the style when selecting a item, just add the style to
.selected
If you want in focus, and remove the class when there is no focus, you may add an eventlistener to control that.
I am trying to create a to-do list in HTML, CSS and pure JS.
const dSubmit = document.getElementById('submit');
const storeData = [];
let typer = document.getElementById('type');
let input = document.getElementById('text');
const list = document.getElementById('listHolder');
dSubmit.addEventListener("click", (e) => {
e.preventDefault();
if (input.value == "") {
typer.innerHTML = "Please enter a task";
} else {
typer.innerHTML = "";
store();
}
});
function store() {
const tData = document.getElementById('text').value;
storeData.push(tData);
updater();
input.value = "";
}
function deleter (index) {
storeData.splice(index, 1);
updater();
}
function updater() {
let htmlCode = "";
storeData.forEach(function(item, index){
htmlCode += "<div class='test'><div id = "+ index +">" + item + "</div><div class='sideBtn'><button type='button' class='edit' onClick= 'editF("+ index +")'>Edit</button><button class='delBtn' onClick= 'deleter("+ index +")'>Delete</button> </div> </div>"
})
list.innerHTML = htmlCode;
}
function editF (index) {
let tempOne = document.getElementById(index);
let tempTwo = "<input id='inputText"+String(index)+"' type='text' name='task' value ='" + String(storeData[index]) + "'><button id='saveText"+String(index)+"' onClick= 'save("+index+")' >Save</button>"
tempOne.innerHTML = tempTwo;
}
function save (index) {
console.log('test1')
let tempOne= document.getElementById('saveText'+String(index));
let tempTwo = document.getElementById('inputText'+String(index));
console.log('test2')
tempOne.addEventListener("click", function foo (){
console.log('test3')
storeData.splice(index,1,tempTwo.value)
updater()
}
)
}
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8">
<title>To Do List</title>
</head>
<body>
<h1>To-do-list</h1>
<form>
<label for="task">Please enter item:</label>
<input type="text" name="task" id="text">
<button id="submit">Submit</button>
</form>
<div id='type'></div>
<div>List:</div>
<div id="listHolder" class="test"></div>
<script type="text/javascript" src="script.js"></script>
</body>
</html>
I am facing problems with the save function. If I edit an item in the to-do list and click the save button, the function executes up to the point of console.log('test2'). If I click save again the function executes in its entirety.
I would like to ask why the first click results in execution of the save function up to 'test2'?
Additionally would anyone be kind enough to critique my JS? are there things in dire need of improvement? or is there a more practical/efficient method of writing my JS code?
Thank you for your help in advance.
After the 'test2' log, you are adding an event listener, and the rest of the code is inside of the listener block. The code in the listener block is only executed once that listener receives a 'click' event, which is why it works the second time.
I’m trying to make a single web page with p5.js, but at some moment I create an input and the value of the input I want to transform into a html tag (more specifically ‘h3’). I already tried the “.html()” as this example: [examples | p5.js], but for some reason this doesn’t work in my context. I’ll let my code below:
let inputName, bttName, yourName;
function setup() {
let inputDiv = createDiv();
inputDiv.id("input-section");
inputDiv.parent("sobre");
inputName = createInput();
inputName.addClass("input-name");
inputName.parent("input-section");
bttName = createButton('enter');
bttName.addClass('btt-name');
bttName.parent("input-section");
bttName.mousePressed(sendName);
}
function sendName() {
let userName = inputName.value();
yourName.html(userName);
}
I need this in as a variable, because after I’ll format it inside a div in css. Is there another way to transform this value?
Thanks
If I'm understanding correctly, you're wanting to output the name that's entered into a h3 element?
In that case you could just use:
yourName = createElement('h3', userName);
like they've done in that reference you linked.
Here's a running example:
let inputName, bttName, yourName;
function setup() {
let inputDiv = createDiv();
inputDiv.id("input-section");
inputName = createInput();
inputName.addClass("input-name");
inputName.parent("input-section");
bttName = createButton('enter');
bttName.addClass('btt-name');
bttName.parent("input-section");
bttName.mousePressed(sendName);
}
function sendName() {
let userName = inputName.value();
yourName = createElement('h3', userName);
}
html, body {
margin: 0;
padding: 0;
}
canvas {
display: block;
}
<!DOCTYPE html>
<html lang="en">
<head>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/p5.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.4.0/addons/p5.sound.min.js"></script>
<link rel="stylesheet" type="text/css" href="style.css">
<meta charset="utf-8" />
</head>
<body>
<script src="sketch.js"></script>
</body>
</html>
I am creating a simple to do list using jQuery and local storage. I am also trying to add a button for each li I add to clear the item from the list. My list does not stick upon refresh and I can't figure out how to load the button, does the button need to happen on the HTML side?
The adding to the list functions work great its just the storage to local storage that I seem to be missing something.
I created a jsfiddle for this code and the local storage seems to work fine but it will not work on my xampp. Also I can get the done button to appear but it won't removeItem.
https://jsfiddle.net/blen6035/287pc153/7/
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Task List</title>
<link rel="stylesheet" href="main.css">
<script src="https://code.jquery.com/jquery-3.4.1.min.js"></script>
<script src="tasks.js"></script>
</head>
<body>
<aside>
<h2>Add a task</h2>
<label for="task">Task:</label>
<input type="text" id="task" name="task"><br>
<label> </label>
<input type="button" id="add" name="add" value="Add Task">
</aside>
<main>
<h1>Task list</h1>
<ul id="listOfTasks"></ul>
</main>
<footer></footer>
</body>
</html>
"use strict"
$(document).ready(function() {
let listOfTasks = JSON.parse( localStorage.getItem("tasks"));
if( listOfTasks == undefined ){
listOfTasks = [];
}
for( let i = 0; i < listOfTasks.length; i++){
let li = $('<li> Done
</li>').text(listOfTasks[i]);
$('#listOfTasks').append(li);
}
$('#add').click(function(){
let task = $('#task').val();
listOfTasks.push(task);
localStorage.setItem("tasks", JSON.stringify(listOfTasks)
);
let li = $('<li></li>').text(task);
$('#listOfTasks').append('<li>'+ task +'<input type="submit"
class="done" value= "Done">' + '</li>');
$('#task').val(' ').focus();
});
$('.done').on('click', '.delete',function(){
$(this).parent().remove();
});
/*$('#done').click(function(){
localStorage.removeItem;
$('#listOfTasks').html('');
});*/
}); // end ready
Is this what you are trying to do ?
Note that I had to polyfill local storage to make this work in a snippet, replace fakeLocalStorage by localStorage
const listOfTasksElement = $('#listOfTasks')
const taskInputElement = $('#task')
const listOfTasks = JSON.parse(fakeLocalStorage.getItem('tasks')) || []
const updateTasks = () => fakeLocalStorage.setItem('tasks', JSON.stringify(listOfTasks))
const addTask = task => {
const taskElement = $('<li></li>').text(task)
const doneElement = $('<span>Done</span>').click(() => {
const index = listOfTasksElement.find('li').index(taskElement)
taskElement.remove()
listOfTasks.splice(index, 1)
updateTasks()
})
taskElement.append(doneElement)
listOfTasksElement.append(taskElement)
listOfTasks.push(task)
updateTasks()
}
listOfTasks.forEach(addTask)
$('#add').click(() => {
addTask(taskInputElement.val())
taskInputElement.val('').focus()
})
<ul id="listOfTasks"></ul>
<input id="task"><button id="add">Add</button>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
// local storage doesn't work in stack overflow snippets,
// this is just a poor in-memory implementation
const fakeLocalStorage = {
_data: {},
setItem(k, v) { return this._data[k] = v },
getItem(k) { return this._data.hasOwnProperty(k) ? this._data[k] : null }
}
</script>