JS form validation / new element is created when it shouldnt be - javascript

I'm new to js and for learning purposes I'm creting an application, where you can add and delete comments. I added a validation on the text input field and it displays an error when you try to submit an empty comment. Error message appears as it should, but the li element still gets created, when it shouldnt. It should only be added when the input is not empty. Can anyone help me with identifying my mistake?
let form = document.getElementById('form');
let commentList = document.getElementById('allComments');
const errorElement = document.getElementById('error');
// form submit event
form.addEventListener('submit', addComment);
// delete comments
commentList.addEventListener('click', removeComment);
//
// add comment to the list
function addComment(e) {
e.preventDefault();
// get input value
let newComment = document.getElementById('comment').value;
// create new li element
let li = document.createElement('li');
// add a class
li.className = 'list-group-item d-flex justify-content-between';
// add a text node with input value
li.appendChild(document.createTextNode(newComment));
// create delete button element
let deleteButton = document.createElement('button');
// add classes on delete button
deleteButton.className = 'btn btn-danger btn-sm float-right delete';
// append text node
deleteButton.appendChild(document.createTextNode('X'));
// append button to li
li.appendChild(deleteButton);
// append li to list
commentList.appendChild(li);
// add error text if input field is empty when submitting
let messages = [];
if (newComment.value === '' || newComment.value == null) {
messages.push('You cannot submit an empty comment')
}
if (messages.length > 0) {
errorElement.innerText = messages.join(', ');
}
else {
}
}
// remove comment
function removeComment(e) {
if (e.target.classList.contains('delete')) {
if(confirm('Are you sure you want to remove this comment?')) {
let li = e.target.parentElement;
commentList.removeChild(li);
}
}
}
body {
/* font-family: 'Kumar One', cursive; */
font-family: 'Mukta', sans-serif;
}
header {
background-color: rgb(68, 139, 66);
}
header h1 {
font-size: 40px;
font-weight: 400;
}
form {
margin-bottom: 20px;
}
.form-control {
margin-bottom: 5px;
}
<!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 href="https://cdn.jsdelivr.net/npm/bootstrap#5.1.3/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-1BmE4kWBq78iYhFldvKuhfTAU6auU8tT94WrHftjDbrCEXSU1oBoqyl2QvZ6jIW3" crossorigin="anonymous">
<link rel="stylesheet" href="style.css">
<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=Kumar+One&family=Mukta:wght#200;400&display=swap"
rel="stylesheet">
<title>Document</title>
</head>
<body>
<header class="text-white p-4 mb-3">
<div class="container">
<div class="col-md-6">
<h1>Adding items</h1>
</div>
</div>
</header>
<div class="container">
<div class="card card-body">
<h2 class="title">Add a comment</h2>
<form class="form-inline col-3 row" id="form">
<input type="text" class="form-control" id="comment">
<div id="error" class="text-danger"></div>
<button class="btn btn-primary" type="submit">Submit</button>
</form>
<h2 class="title">All comments</h2>
<ul id="allComments" class="list-group">
<li class="list-group-item d-flex justify-content-between">comment 1 <button class="btn btn-danger btn-sm float-right delete">X</button></li>
<li class="list-group-item d-flex justify-content-between">comment 2 <button class="btn btn-danger btn-sm float-right delete">X</button></li>
<li class="list-group-item d-flex justify-content-between">comment 3 <button class="btn btn-danger btn-sm float-right delete">X</button></li>
<li class="list-group-item d-flex justify-content-between">comment 4 <button class="btn btn-danger btn-sm float-right delete">X</button></li>
</ul>
</div>
</div>
<script src="script.js"></script>
</body>
</html>

You should use the following validation at the top of the addComment and return if you find comment is empty so the next statements do not execute.
if (newComment.value === '' || newComment.value == null) {
messages.push('You cannot submit an empty comment')
// Add return to exit from function
return;
}

Related

how can I resolve sweetalert background distortion?

enter image description here
Upper image is the Sign-in page.
I added sweetalert, and it goes wrong like below.
(the alert set in the middel, and my sign-in form goes up! It should be located in the middle!)
(I added the alert appear when the ID or password value is null or empty.)
login equals sign-in
what's wrong with my code?
Here is my full code
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<script src="https://cdn.jsdelivr.net/npm/sweetalert2#9"></script>
<meta name="description" content="">
<meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
<meta name="generator" content="Hugo 0.101.0">
<title>Floating labels example · Bootstrap v4.6</title>
<!-- Bootstrap core CSS -->
<!-- <link href="/css/bootstrap.min.css" rel="stylesheet">-->
<script src="https://code.jquery.com/jquery-3.6.0.min.js"
integrity="sha256-/xUj+3OJU5yExlq6GSYGSHk7tPXikynS7ogEvDej/m4=" crossorigin="anonymous"></script>
<link rel="canonical" href="https://getbootstrap.com/docs/5.1/examples/product/">
<!-- Bootstrap core CSS -->
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.2/dist/css/bootstrap.min.css" rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC" crossorigin="anonymous">
<style>
.bd-placeholder-img {
font-size: 1.125rem;
text-anchor: middle;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
}
#media (min-width: 768px) {
.bd-placeholder-img-lg {
font-size: 3.5rem;
}
}
</style>
<!-- Custom styles for this template -->
<link href="/css/floating-labels.css" rel="stylesheet">
</head>
<body>
<div class="form-signin" style="max-width: 520px">
<div class="text-center mb-4">
<!-- TODO 로그인페이지 로고 추가할 자리 -->
<!-- <img class="mb-4" src="/brand/bootstrap-solid.svg" alt="" width="72" height="72">-->
<h1 class="h3 mb-3 font-weight-normal">로그인 </h1>
</div>
<div class="form-label-group">
<input id="user_id" class="form-control" placeholder="id" required autofocus>
<label for="inputId">ID를 입력하세요</label>
</div>
<div class="form-label-group">
<input type="password" id="password" class="form-control" placeholder="Password" required>
<label for="inputPassword">Password를 입력하세요</label>
</div>
<div>
<button class="btn btn-outline-primary form-control" id="loginBtn" onclick="login()">로그인</button>
</div>
<hr class="mb-4">
<div class="btn-group row" style="width:100%; --bs-gutter-x: 0">
<button class="btn btn-sm btn btn-outline-secondary btn-block col-4" type="button" style="font-size:16px;">아이디
찾기
</button>
<button class="btn btn-sm btn btn-outline-secondary btn-block col-4" type="button" style="font-size:16px;">비밀번호
찾기
</button>
<button class="btn btn-sm btn btn-outline-secondary btn-block col-4" type="button" style="font-size:16px;"
onclick="joinBtn()">회원가입
</button>
</div>
<p class="mt-5 mb-3 text-muted text-center">© 2017-2022</p>
</div>
</body>
</html>
<script>
var input = document.getElementById("password");
input.addEventListener("keypress", function (event) {
if (event.key === "Enter") {
event.preventDefault();
document.getElementById("loginBtn").click();
}
});
var passwordForm = document.querySelector("#password");
function login() {
let userIdValue = document.querySelector("#user_id").value;
let passwordValue = document.querySelector("#password").value;
if (userIdValue == null || userIdValue == "") {
document.querySelector("#user_id").focus();
Swal.fire(
'ID가 비었습니다!',
'로그인 할 계정의 ID를 입력해주세요!',
'question'
)
return;
}
if (passwordValue == null || passwordValue == "") {
document.querySelector("#password").focus();
Swal.fire(
'비밀번호가 비었습니다!',
'로그인 할 계정의 비밀번호를 입력해주세요!',
'question'
)
return;
}
let info = {
userId: userIdValue,
password: passwordValue
}
$.ajax({
url: "/login/check/api",
method: "POST",
contentType: "application/Json",
data: JSON.stringify(info),
success: function (a) {
location.href = "/"
},
error: function (a, b) {
let errorA = a
Swal.fire({
icon: 'error',
title: '로그인 실패',
text: errorA.responseText,
})
//alert(a.responseText);
}
})
}
function joinBtn() {
location.href = "/join/form"
}
</script>
let me know how can I solve this problem
Before the alert comes out, I think the HTML should be on the screen first to solve the problem, but I don't know what to do.

I want to make a todo list but I am stuck at the start, where am I going wrong in this code?

I want to add li to the ul element with the value entered by user in the input area.
This is the error I am getting in console:
[Error] TypeError: document.getElementsByClassName("list-group").appendChild is not a function. (In 'document.getElementsByClassName("list-group").appendChild("li")', 'document.getElementsByClassName("list-group").appendChild' is undefined)
additem (script.js:7)
//this is my javascript code-->
function additem() {
var task = document.getElementsByClassName("input-group-text").value;
var li = document.createElement("li");
li.classList.add("list-group-item");
li = "task";
document.getElementsByClassName("list-group").appendChild("li");
}
document.getElementById("button").addEventListener("click",additem);
//<--!this is my html code-->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>LearnCodeOnline</title>
<link rel="stylesheet" href="./style.css" />
<link
rel="stylesheet"
href="https://stackpath.bootstrapcdn.com/bootstrap/4.4.1/css/bootstrap.min.css"
/>
</head>
<body class="bg-dark">
<div class="container bg-warning p-4">
<h1 class="text-center">LearnCodeOnline</h1>
<div class="input-group">
<span class="input-group-text">todo</span>
<textarea class="form-control" aria-label="With textarea"></textarea>
</div>
<button id="button" class="float-right">Add</button>
<ul class="list-group">
<li class="list-group-item">An item</li>
</ul>
<!-- <button
type="button"
class="btn btn-success btn-lg mt-4 mx-auto d-block sort-btn"
>
Sort courses
</button> -->
</div>
</body>
</html>
JS:-
function additem() {
var task = document.getElementsByClassName("form-control")[0].value;
var li = document.createElement("li");
li.classList.add("list-group-item");
li.innerText = task;
document.getElementsByClassName("list-group")[0].appendChild(li);
}
document.getElementById("button").addEventListener("click",additem);
Instead of doing .appendChild("li"), we'll give it an element and not string as it takes the element and not string
getElementsByClassName() returns an array so we will take the item at 0th index of the array in both the functions where it is there
also instead of setting li = "task" like this, we'll have to set its text by li.innerText = task

What are the methods to limit the number and time of alerts?

when I click on the "Todo Ekleyin" button, I get a warning. However, I would like this alert to appear only once per press, not multiple times, and can be pressed again after the alert disappears. How can I achieve this and?
Thank you in advance for your answer, good work. (If there is a method other than the method you suggested, I would be glad if you can write its name.)
// Tüm Elementleri Seçme
const form = document.querySelector("#todo-form");
const todoInput = document.querySelector("#todo");
const todoList = document.querySelector(".list-group");
const firstCardBody = document.querySelectorAll(".card-body")[0];
const secondCardBody = document.querySelectorAll(".card-body")[1];
const filter = document.querySelector("#filter");
const clearButton = document.querySelector("#clear-todos");
eventListeners();
function eventListeners() { // Tüm Event Listenerlar
form.addEventListener("submit", addTodo);
}
function addTodo(e) {
const newTodo = todoInput.value.trim();
if (newTodo === "") { // Alarm Verme
showAlert("danger","Lütfen Bir Todo Giriniz");
}
else {
addTodoToUI(newTodo);
}
addTodoToUI(newTodo);
e.preventDefault();
}
function showAlert(type,message){
const alert = document.createElement("div");
alert.className = `alert alert-${type}`;
alert.textContent = message;
firstCardBody.appendChild(alert);
//setTimeout
setTimeout(function(){
alert.remove();
}, 1000);
}
function addTodoToUI(newTodo) { // String Değerini List Item olarak Ekleyecek.
// List Item Oluşturma.
const listItem = document.createElement("li");
// Link Oluşturma
const link = document.createElement("a");
link.href = "#";
link.className = "delete-item";
link.innerHTML = "<i class = 'fa fa-remove'></i>";
listItem.className = "list-group-item d-flex justify-content-between";
// Text Node
listItem.appendChild(document.createTextNode(newTodo));
listItem.appendChild(link);
// Todo List'e List Item'ı Ekleme
todoList.appendChild(listItem);
// Ekleme Sonrası Input'tan yazı Silme
todoInput.value = "";
}
// Todo Ekleme Bilgi Mesajı
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<meta http-equiv="X-UA-Compatible" content="ie=edge" />
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" />
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0/css/bootstrap.min.css"
integrity="sha384-Gn5384xqQ1aoWXA+058RXPxPg6fy4IWvTNh0E263XmFcJlSAwiGgFAW/dAiS6JXm" crossorigin="anonymous" />
<title>Todo List</title>
</head>
<body>
<div class="container" style="margin-top: 20px">
<div class="card row">
<div class="card-header">Todo List</div>
<div class="card-body">
<form id="todo-form" name="form">
<div class="form-row">
<div class="form-group col-md-6">
<input class="form-control" type="text" name="todo" id="todo"
placeholder="Bir Todo Girin" />
</div>
</div>
<button type="submit" class="btn btn-danger">Todo Ekleyin</button>
</form>
<hr />
<!-- <div class="alert alert-danger" role="alert">
This is a danger alert—check it out!
</div> -->
</div>
<div class="card-body">
<hr />
<h5 class="card-title" id="tasks-title">Todolar</h5>
<div class="form-row">
<div class="form-group col-md-6">
<input class="form-control" type="text" name="filter" id="filter"
placeholder="Bir Todo Arayın" />
</div>
</div>
<hr />
<ul class="list-group">
<!-- <li class="list-group-item d-flex justify-content-between">
Todo 1
<a href = "#" class ="delete-item">
<i class = "fa fa-remove"></i>
</a>
</li>-->
</ul>
<hr />
<a id="clear-todos" class="btn btn-dark" href="#">Tüm Taskları Temizleyin</a>
</div>
</div>
</div>
<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>
<script src="berkay.js"></script>
</body>
</html>
You can put an integer in your alert function and every using array increase a one more.
For example, if you want after 5 times don't show alert.
var a = 0;
var b = true;
if (newTodo === "" || b) { // Alarm Verme
showAlert("danger","Please Give me a Todo!");
a++;
if(a == 5 ){
b = false;
}
}

Change li element class when pressing a button and in that css class change background color

I have a todo app.
I managed to make it show an input when pressing the add button and to delete randomly, but when I click the done button I want to change the li element class to a class that has css background color red, but it doesn't work. I tried with jquery but it still doesn't work. The red background suggests that the task is done.
index.html
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<link rel="stylesheet" type="text/css" href="stil.css">
<!-- Latest compiled and minified CSS -->
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/css/bootstrap.min.css">
<!-- jQuery library -->
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<!-- Latest compiled JavaScript -->
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/3.4.0/js/bootstrap.min.js"></script>
<meta charset="utf-8">
<title></title>
</head>
<body>
<div class="centru">
<div class="row">
<div class="col-lg-12">
<h2>TO DO LIST</h2>
</div>
</div>
<div class="row">
<div class="col-lg-6">
<input type="text" class="form-control" id="usr" placeholder="Input task...">
</div>
<div class="col-lg-6">
<button type="button" class="btn btn-primary" onclick="adauga()">Add task</button>
</div>
</div>
<div class="row">
<div class="col-lg-12">
<ul class="list-group" id="lista1">
</ul>
</div>
</div>
</div>
<script src="script.js"></script>
</body>
</html>
script.js
function adauga() {
var inp = document.getElementById('usr').value;
var list = document.getElementById('lista1');
var li = document.createElement('li');
var lungime = document.getElementById("lista1").getElementsByTagName('li').length;
for(var i = 0; i < lungime ; i++) {
li.setAttribute("id",i);
}
li.appendChild(document.createTextNode(inp));
var button = document.createElement("button");
button.innerHTML = "Delete";
button.setAttribute("class","btn btn-primary ste");
button.setAttribute("onclick","sterge()");
//button.setAttribute("class","ste");
li.appendChild(button);
list.appendChild(li);
//////////////////////////////////////
var button2 = document.createElement("button");
button2.innerHTML = "Done";
button2.setAttribute("class","btn btn-primary done");
button2.setAttribute("onclick","done()");
li.appendChild(button2);
list.appendChild(li);
}
function change() {
li.setAttribute("class","xxx");
}
function sterge() {
$('body').on('click','.ste', function(){
$(this).parent().remove();
});
}
function done() {
$('body').on('click','done',function(){
$(this).parent().setAttribute("class","btn btn-primary done xxx");
});
}
stil.css
.centru {
width: 600px ;
margin-left: auto ;
margin-right: auto ;
}
.lix {
padding-right: 20px;
}
.xxx {
background-color: red;
color:red;
}
you can use addClass function on done function like this
function done() {
$('body').on('click','.done',function(){
$(this).parent().addClass("btn btn-primary done xxx");
});
}

LocalStorage removes the wrong value

I keep having the same issue again and again : When I add a task, it gets added to the localStorage correctly. But once I have multiple tasks and I click complete on a random one, sometimes it happens that the LocalStorage removes the task before it or after it. I can't figure out a way how to let it work.
let addBtn = document.getElementById("addButton");
let textInput = document.getElementById("textInput");
let mainList = document.getElementById("mainList");
let storage = JSON.parse(localStorage.getItem("toDos")) || [];
if (storage.length != 0){
for (let i=0; i<storage.length;i++){
addTask(mainList, storage[i]);
};
};
function addTask(list,task){
var newTask = document.createElement("li");
newTask.textContent=task
newTask.className="task d-flex justify-content-between list-group-item bg-primary mt-2";
addCompleteBtn(newTask);
list.appendChild(newTask);
}
function addCompleteBtn (newTask){
let completeBtn = document.createElement("button");
completeBtn.className="btn btn-success completeBtn";
completeBtn.textContent="Completed";
newTask.appendChild(completeBtn);
};
addBtn.addEventListener("click", ()=>{
if(textInput.value === ""){
alert("Error: The field is either empty or you entered more than 100 characters!");
}else{
storage.push(textInput.value);
addTask(mainList, textInput.value);
textInput.value="";
localStorage.setItem("toDos",JSON.stringify(storage));
};
});
mainList.addEventListener("click",(evt)=>{
if (evt.target.className==="btn btn-success completeBtn") {
let listItem = evt.target.parentNode;
let mainUl = listItem.parentNode;
let toBeRemoved = listItem.textContent;
storage.splice(storage.indexOf(toBeRemoved),1);
mainUl.removeChild(listItem);
localStorage.setItem("toDos",JSON.stringify(storage));
};
});
<!doctype html>
<html lang="en">
<head>
<!-- Required meta tags -->
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<!-- Bootstrap CSS -->
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.3/css/bootstrap.min.css" integrity="sha384-MCw98/SFnGE8fJT3GXwEOngsV7Zt27NXFoaoApmYm81iuXoPkFOJwJ8ERdknLPMO" crossorigin="anonymous">
<link rel="stylesheet" href="style.css">
<title>To-do-list App</title>
</head>
<body>
<div class="jumbotron bg-info">
<div class="container">
<h1 class="display-4 text-center">Task List</h1>
<p class="lead text-center">Click on the Add button to add a task</p>
</div>
</div>
<div class="container">
<div class="firstInput input-group mb-5">
<div class="input-group-prepend">
<button class="btn btn-primary" type="button" id="addButton">Add Task</button>
</div>
<input type="text" title='Enter a Task' class="form-control" id="textInput" maxlength="200">
</div>
</div>
<ul class='tasksList container' id="mainList">
</ul>
<script src="script.js"></script>
</body>
</html>
Shows all the values in the LocalStorage
Once task 2 is removed, task 3 is removed from the Storage instead
this is the specific part that causes me issues :
mainList.addEventListener("click",(evt)=>{
if (evt.target.className==="btn btn-success completeBtn") {
let listItem = evt.target.parentNode;
let mainUl = listItem.parentNode;
let toBeRemoved = listItem.textContent;
/* This is the part of code causing me issues
storage.splice(storage.indexOf(toBeRemoved),1);
*/
mainUl.removeChild(listItem);
localStorage.setItem("toDos",JSON.stringify(storage));
};
});
The problem is here let toBeRemoved = listItem.textContent;,this will return the text content of all elements inside that li. So if you add a task named 'Task 1', when you press Completed the value of toBeRemoved will be Task 1Completed since this will return the text of the button as well since your button is a child of the li.
So change let toBeRemoved = listItem.textContent; to let toBeRemoved = listItem.childNodes[0].nodeValue; and you should be fine, this will get the text of the li only.

Categories

Resources