I've build a simple Expense Tracker that contains 3 inputs
Name input
Date input
Amount input
After the user fills these 3 inputs, they can click a button to add the expense into a table and store it there. If they want to remove an expense from the table, they can click the "REMOVE ENTRY" button.
If the table is empty, the "No expenses added yet!" tr element is shown. Once an expense gets added, the tr element with the message disappears. However, if I add an expense to the table and then remove it, the tr element with the message no longer appears. Is there any way how I can make it re-appear again?
let nameInput = document.querySelector(".name");
let dateInput = document.querySelector(".date");
let amountInput = document.querySelector(".amount");
let button = document.querySelector(".add-btn");
let ifEmpty = document.querySelector(".if-empty");
let table = document.querySelector("table");
button.addEventListener("click", function() {
ifEmpty.remove();
// CREATE THE EXPENSE
let holder = document.createElement("tr");
let row = document.createElement("td");
let btnRow = document.createElement("td");
let removeButton = document.createElement("button");
table.appendChild(holder);
holder.appendChild(row).textContent = nameInput.value;
holder.appendChild(row.cloneNode(true)).textContent = dateInput.value;
holder.appendChild(row.cloneNode(true)).textContent = amountInput.value;
holder.appendChild(btnRow);
btnRow.appendChild(removeButton).textContent = "REMOVE ENTRY";
// REMOVE THE EXPENSE
removeButton.addEventListener("click", function() {
holder.remove();
});
/* TRIED THIS TO MAKE THE ELEMENT RE-APPEAR IF THE TABLE IS EMPTY BUT
IT DIDN'T WORK */
if (!table.contains(holder)) {
table.appendChild(ifEmpty);
}
});
.container {
text-align: center;
}
h1 {
font-size: 3.5em;
}
h2 {
font-size: 2em;
margin-bottom: 0.5em;
color: green;
}
span {
font-size: 1.4em;
}
.date-amount-input {
margin-top: 0.5em;
}
input {
height: 28px;
}
.name {
padding-right: 5em;
}
.amount {
padding-right: 15.35em;
}
.amount-text {
margin-left: 0.4em;
}
.date {
padding-right: 18.8em;
}
.add-btn {
margin-top: 0.9em;
padding: 0.6em;
font-size: 1.1em;
background: green;
color: white;
border: none;
border-radius: 5px;
}
.add-btn:hover, .add-btn:focus {
cursor: pointer;
background: rgb(3, 177, 3);
}
table {
margin: 0 auto;
margin-top: 2em;
width: 50%;
height: 80px;
}
tr {
height: 40px;
}
table, th, td{
border: 1px solid rgba(0, 0, 0, 0.103);
border-collapse: collapse;
}
.empty-text {
font-size: 0.93em;
}
.if-empty {
background: rgba(0, 0, 0, 0.055);
}
<body>
<div class="container">
<h1>Expense Tracker</h1>
<h2>Add A New Item</h2>
<div class="name-input">
<span class="name-text">Name: </span>
<input type="text" class="name" placeholder="Where was the expense made" size="117">
</div>
<div class="date-amount-input">
<span>Date: </span>
<input class="date" type="date">
<span class="amount-text">Amount: </span>
<input class="amount" type="text">
</div>
<button class="add-btn">Add Expense</button>
<table>
<tr>
<th>Name</th>
<th>Date</th>
<th>Amount</th>
</tr>
<tr class="if-empty">
<td colspan = "4">
<span class="empty-text">No expenses added yet!</span>
</td>
</tr>
</table>
</div>
<script src="main.js"></script>
</body>
I am still a beginner in JS, so any tips will be aprecitated.
You do an ifEmpty.remove();, that actually removes the element. Once it is removed it is gone and you can't make it reappear without creating it again.
The easier solution may be to hide it instead of removing it.
You can use ifEmpty.style.display = "none" to hide it and ifEmpty.style.display = "table-row" to show it again
Show/hide can be done with pure CSS, display as table-row if it is the last <tr>. Make sure new rows are added inside the same <tbody>.
tr.if-empty {
background: rgba(0, 0, 0, 0.055);
display: none;
}
tr:last-child.if-empty {
display: table-row;
}
let nameInput = document.querySelector(".name");
let dateInput = document.querySelector(".date");
let amountInput = document.querySelector(".amount");
let button = document.querySelector(".add-btn");
let ifEmpty = document.querySelector(".if-empty");
let table = document.querySelector("table > tbody");
button.addEventListener("click", function() {
// CREATE THE EXPENSE
let holder = document.createElement("tr");
let row = document.createElement("td");
let btnRow = document.createElement("td");
let removeButton = document.createElement("button");
table.appendChild(holder);
holder.appendChild(row).textContent = nameInput.value;
holder.appendChild(row.cloneNode(true)).textContent = dateInput.value;
holder.appendChild(row.cloneNode(true)).textContent = amountInput.value;
holder.appendChild(btnRow);
btnRow.appendChild(removeButton).textContent = "REMOVE ENTRY";
// REMOVE THE EXPENSE
removeButton.addEventListener("click", function() {
holder.remove();
});
});
.container {
text-align: center;
}
h1 {
font-size: 3.5em;
}
h2 {
font-size: 2em;
margin-bottom: 0.5em;
color: green;
}
span {
font-size: 1.4em;
}
.date-amount-input {
margin-top: 0.5em;
}
input {
height: 28px;
}
.name {
padding-right: 5em;
}
.amount {
padding-right: 15.35em;
}
.amount-text {
margin-left: 0.4em;
}
.date {
padding-right: 18.8em;
}
.add-btn {
margin-top: 0.9em;
padding: 0.6em;
font-size: 1.1em;
background: green;
color: white;
border: none;
border-radius: 5px;
}
.add-btn:hover, .add-btn:focus {
cursor: pointer;
background: rgb(3, 177, 3);
}
table {
margin: 0 auto;
margin-top: 2em;
width: 50%;
height: 80px;
}
tr {
height: 40px;
}
table, th, td{
border: 1px solid rgba(0, 0, 0, 0.103);
border-collapse: collapse;
}
.empty-text {
font-size: 0.93em;
}
tr.if-empty {
background: rgba(0, 0, 0, 0.055);
display: none;
}
tr:last-child.if-empty {
display: table-row;
}
<body>
<div class="container">
<h1>Expense Tracker</h1>
<h2>Add A New Item</h2>
<div class="name-input">
<span class="name-text">Name: </span>
<input type="text" class="name" placeholder="Where was the expense made" size="117">
</div>
<div class="date-amount-input">
<span>Date: </span>
<input class="date" type="date">
<span class="amount-text">Amount: </span>
<input class="amount" type="text">
</div>
<button class="add-btn">Add Expense</button>
<table>
<tbody>
<tr>
<th>Name</th>
<th>Date</th>
<th>Amount</th>
</tr>
<tr class="if-empty">
<td colspan = "4">
<span class="empty-text">No expenses added yet!</span>
</td>
</tr>
</tbody>
</table>
</div>
<script src="main.js"></script>
</body>
Instead of deleting the element from page, you can simply hide it with CSS.
Add following class in CSS:
.hide{
display: none;
}
Now, create a function in JavaScript that checks if the table if Empty excluding header row and ifEmpty row:
let toggleIfEmpty = () => {
if(table.getElementsByTagName('tr').length <= 2){
ifEmpty.classList.remove("hide");
} else {
ifEmpty.classList.add("hide");
}
};
Call this function on eventListener:
removeButton.addEventListener("click", function() {
holder.remove();
toggleIfEmpty();
});
Then call the function again instead of appending the child element:
Do this: toggleIfEmpty();
Instead of:
if (!table.contains(holder)) {
table.appendChild(ifEmpty);
}
It will work.
Full updated JS for your reference:
let nameInput = document.querySelector(".name");
let dateInput = document.querySelector(".date");
let amountInput = document.querySelector(".amount");
let button = document.querySelector(".add-btn");
let ifEmpty = document.querySelector(".if-empty");
let table = document.querySelector("table");
let toggleIfEmpty = () => {
if(table.getElementsByTagName('tr').length <= 2){
ifEmpty.classList.remove("hide");
} else {
ifEmpty.classList.add("hide");
}
};
button.addEventListener("click", function() {
// CREATE THE EXPENSE
let holder = document.createElement("tr");
let row = document.createElement("td");
let btnRow = document.createElement("td");
let removeButton = document.createElement("button");
table.appendChild(holder);
holder.appendChild(row).textContent = nameInput.value;
holder.appendChild(row.cloneNode(true)).textContent = dateInput.value;
holder.appendChild(row.cloneNode(true)).textContent = amountInput.value;
holder.appendChild(btnRow);
btnRow.appendChild(removeButton).textContent = "REMOVE ENTRY";
// REMOVE THE EXPENSE
removeButton.addEventListener("click", function() {
holder.remove();
toggleIfEmpty();
});
/* TRIED THIS TO MAKE THE ELEMENT RE-APPEAR IF THE TABLE IS EMPTY BUT
IT DIDN'T WORK */
/* if (!table.contains(holder)) {
table.appendChild(ifEmpty);
} */
toggleIfEmpty();
});
You can do something like this, inside of the eventListener for the remove entry button you can check if the number of children elements inside the table is less than or equal to 1 (including the name date and amount element) in that case there will be no entries, and you can append the message.
In this solution, im creating a placeholder for the "no entries" message, and creating that everytime the message has to be appended, you could use the display property of an element to hide or show it accordingly instead of creating a new element for each session
let nameInput = document.querySelector(".name");
let dateInput = document.querySelector(".date");
let amountInput = document.querySelector(".amount");
let button = document.querySelector(".add-btn");
let ifEmpty = document.querySelector(".if-empty");
let table = document.querySelector("table");
const emptyMessage = ifEmpty;
button.addEventListener("click", function() {
ifEmpty.remove();
// CREATE THE EXPENSE
let holder = document.createElement("tr");
let row = document.createElement("td");
let btnRow = document.createElement("td");
let removeButton = document.createElement("button");
// REMOVE THE EXPENSE
removeButton.addEventListener("click", function() {
holder.remove();
if (table.children.length <= 1) table.appendChild(emptyMessage)
});
table.appendChild(holder);
holder.appendChild(row).textContent = nameInput.value;
holder.appendChild(row.cloneNode(true)).textContent = dateInput.value;
holder.appendChild(row.cloneNode(true)).textContent = amountInput.value;
holder.appendChild(btnRow);
btnRow.appendChild(removeButton).textContent = "REMOVE ENTRY";
// TRIED THIS BUT IT DIDN'T WORK
});
.container {
text-align: center;
}
h1 {
font-size: 3.5em;
}
h2 {
font-size: 2em;
margin-bottom: 0.5em;
color: green;
}
span {
font-size: 1.4em;
}
.date-amount-input {
margin-top: 0.5em;
}
input {
height: 28px;
}
.name {
padding-right: 5em;
}
.amount {
padding-right: 15.35em;
}
.amount-text {
margin-left: 0.4em;
}
.date {
padding-right: 18.8em;
}
.add-btn {
margin-top: 0.9em;
padding: 0.6em;
font-size: 1.1em;
background: green;
color: white;
border: none;
border-radius: 5px;
}
.add-btn:hover, .add-btn:focus {
cursor: pointer;
background: rgb(3, 177, 3);
}
table {
margin: 0 auto;
margin-top: 2em;
width: 50%;
height: 80px;
}
tr {
height: 40px;
}
table, th, td{
border: 1px solid rgba(0, 0, 0, 0.103);
border-collapse: collapse;
}
.empty-text {
font-size: 0.93em;
}
.if-empty {
background: rgba(0, 0, 0, 0.055);
}
<body>
<div class="container">
<h1>Expense Tracker</h1>
<h2>Add A New Item</h2>
<div class="name-input">
<span class="name-text">Name: </span>
<input type="text" class="name" placeholder="Where was the expense made" size="117">
</div>
<div class="date-amount-input">
<span>Date: </span>
<input class="date" type="date">
<span class="amount-text">Amount: </span>
<input class="amount" type="text">
</div>
<button class="add-btn">Add Expense</button>
<table>
<tr>
<th>Name</th>
<th>Date</th>
<th>Amount</th>
</tr>
<tr class="if-empty">
<td colspan = "4">
<span class="empty-text">No expenses added yet!</span>
</td>
</tr>
</table>
</div>
<script src="main.js"></script>
</body>
Using display property method
replace ifEmpty.remove() with ifEmpty.style.display = 'none to hide it and replace table.appendChild(emptyMessage) with ifEmpty.style.display = 'table-row to show it again
Related
Still learning so bear with me.
I am building a test project where I have a simple input that I show it on the same page as a list. (grocery or to do list project)
So when a user hits the ok button I create a new li inside a ul element. That goes ok.
I want to implement the following though: When the user clicks on the new element (li) I want to change the text decoration to line-though and show a trash icon where it will remove this li element by clicking on it.
I have managed to do that. The problem is that when the user clicks again on the new element (li) I get a second trash image.
I want help to succeed in this: when a user clicks on the element while it has text-decoration = line-through to hide or remove the trash icon and make text-decoration none again.
Here is a code pen for this project to check out. Just insert a new item on the list and then click twice on it: https://codepen.io/dourvas-ioannis/pen/MWVBjNZ
This is the function I am using when the user hits the add button to add a list item:
function addToList(){
let newListItem = document.createElement('li');
newListItem.textContent = userInput.value;
list.appendChild(newListItem);
userInput.value = "";
newListItem.addEventListener('click', function(){
this.style.textDecoration = 'line-through';
let itemButton = document.createElement('a');
itemButton.setAttribute('href', '#');
itemButton.classList.add('trash-image');
itemButton.innerHTML = '<i class="material-icons">delete</i><a/>';
itemButton.addEventListener("click", deleteOneItem);
this.appendChild(itemButton);
});
}
function deleteOneItem(){
this.parentNode.remove();
}
//select from DOM
let allItems = document.querySelector('#allItems');
let button = document.querySelector('#add-button');
let userInput = document.querySelector('#item');
let list = document.querySelector('#list');
let clear = document.querySelector('#clear-button');
//add event listener
button.addEventListener('click', addToList);
clear.addEventListener('click', clearAll);
//functions
function addToList() {
let newListItem = document.createElement('li');
newListItem.textContent = userInput.value;
list.appendChild(newListItem);
userInput.value = "";
newListItem.addEventListener('click', function() {
this.style.textDecoration = 'line-through';
let itemButton = document.createElement('a');
itemButton.setAttribute('href', '#');
itemButton.classList.add('trash-image');
itemButton.innerHTML = '<i class="material-icons">delete</i><a/>';
itemButton.addEventListener("click", deleteOneItem);
this.appendChild(itemButton);
});
}
function deleteOneItem() {
this.parentNode.remove();
}
function clearAll() {
list.innerHTML = "";
}
body {
font-size: 10px;
font-family: Arial, Helvetica, sans-serif;
margin: 0;
background-color: antiquewhite;
}
#container {
width: 80%;
margin: auto;
padding-top: 10px;
background-color: rgb(200, 225, 225);
color: rgb(52, 48, 48);
border-radius: 10px;
}
p {
font-size: 20px;
text-align: center;
padding: 30px, 0px, 5px, 0px;
}
#formdiv {
text-align: center;
}
#item {
size: 100px;
}
#clear {
margin-top: 60px;
text-align: center;
}
li {
list-style-type: none;
font-size: 3.2em;
padding: 0.5em;
margin: 1em;
background-color: lightyellow;
border-radius: 5px;
border: 1px solid grey;
}
.trash-image {
float: right;
margin: -2px 3px 3px 3px;
vertical-align: middle;
height: 4px;
}
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<body>
<br> <br> <br>
<div id='container'>
<p>My list</p>
<br>
<div id="formdiv">
<label for="item">add this.. </label><br>
<input type="text" name="item" id="item">
<button id="add-button"> add </button>
</div>
<div id="allItems">
<ul id="list">
</ul>
</div>
<div id="clear">
<button id="clear-button"> Clear List </button><br> <br> <br>
</div>
</div>
Here's a quick example implementation of the approach I mentioned in the comments. I've just hacked it together quickly, so there's a small difference for the bin.
I've used an img (without a src) instead of a 'character' from the
font. I've styled the img to be 16x16 for the same reason. It also
makes it visible instead of being 0x0 pixels. I also set the cursor.
"use strict";
window.addEventListener('load', onLoad, false);
function onLoad(evt) {
document.querySelector('button').addEventListener('click', onAddBtnClicked, false);
}
function onAddBtnClicked(evt) {
let userText = document.querySelector('input').value;
let newLi = document.createElement('li');
newLi.textContent = userText;
newLi.addEventListener('click', onIncompleteItemClicked, false);
document.querySelector('ul').appendChild(newLi);
}
function onIncompleteItemClicked(evt) {
let clickedLi = this;
clickedLi.classList.toggle('itemComplete');
let binImg = document.createElement('img');
binImg.addEventListener('click', onBinIconClicked, false);
clickedLi.appendChild(binImg);
clickedLi.removeEventListener('click', onIncompleteItemClicked, false);
clickedLi.addEventListener('click', onCompletedItemClicked, false);
}
function onCompletedItemClicked(evt) {
let clickedLi = this;
clickedLi.classList.toggle('itemComplete');
let binImg = clickedLi.querySelector('img');
clickedLi.removeChild(binImg);
clickedLi.removeEventListener('click', onCompletedItemClicked, false);
clickedLi.addEventListener('click', onIncompleteItemClicked, false);
}
function onBinIconClicked(evt) {
let clickedBin = this;
let containingLi = clickedBin.parentNode;
containingLi.remove();
}
.itemComplete {
text-decoration: line-through;
}
li>img {
cursor: pointer;
width: 16px;
height: 16px;
}
<input value='blah-blah'></input><button>Add</button>
<ul></ul>
Add a variable indicating that the icon has been already added.
Check if icon is added on click
If yes - skip
If not - set icon
//select from DOM
let allItems = document.querySelector('#allItems');
let button = document.querySelector('#add-button');
let userInput = document.querySelector('#item');
let list = document.querySelector('#list');
let clear = document.querySelector('#clear-button');
//add event listener
button.addEventListener('click', addToList);
clear.addEventListener('click', clearAll);
//functions
function addToList() {
let newListItem = document.createElement('li');
newListItem.textContent = userInput.value;
list.appendChild(newListItem);
userInput.value = "";
// declare boolean variable
let hasTrashIcon = false
newListItem.addEventListener('click', function() {
// if has thrash icon skip
if (hasTrashIcon) return
// set has trash icon
hasTrashIcon = true
this.style.textDecoration = 'line-through';
let itemButton = document.createElement('a');
itemButton.setAttribute('href', '#');
itemButton.classList.add('trash-image');
itemButton.innerHTML = '<i class="material-icons">delete</i><a/>';
itemButton.addEventListener("click", deleteOneItem);
this.appendChild(itemButton);
});
}
function deleteOneItem() {
this.parentNode.remove();
}
function clearAll() {
list.innerHTML = "";
}
body {
font-size: 10px;
font-family: Arial, Helvetica, sans-serif;
margin: 0;
background-color: antiquewhite;
}
#container {
width: 80%;
margin: auto;
padding-top: 10px;
background-color: rgb(200, 225, 225);
color: rgb(52, 48, 48);
border-radius: 10px;
}
p {
font-size: 20px;
text-align: center;
padding: 30px, 0px, 5px, 0px;
}
#formdiv {
text-align: center;
}
#item {
size: 100px;
}
#clear {
margin-top: 60px;
text-align: center;
}
li {
list-style-type: none;
font-size: 3.2em;
padding: 0.5em;
margin: 1em;
background-color: lightyellow;
border-radius: 5px;
border: 1px solid grey;
}
.trash-image {
float: right;
margin: -2px 3px 3px 3px;
vertical-align: middle;
height: 4px;
}
<link rel="stylesheet" href="https://fonts.googleapis.com/icon?family=Material+Icons">
<body>
<br> <br> <br>
<div id='container'>
<p>My list</p>
<br>
<div id="formdiv">
<label for="item">add this.. </label><br>
<input type="text" name="item" id="item">
<button id="add-button"> add </button>
</div>
<div id="allItems">
<ul id="list">
</ul>
</div>
<div id="clear">
<button id="clear-button"> Clear List </button><br> <br> <br>
</div>
</div>
I have a basic HTML form that takes input from the user about his age, gender, dob, email and contact number. I save it into the local storage as employeeData by making it an object in an array. [{},{},{}]. I also add a User_id that is calculated by a random function generator and display it using the Javascript. An example is mentioned below.
[
{
"U_Id": "1a9f1268-9c74-4cfb-971c-f595cb4a40e1",
"Name": "dsgfdsfds",
"Gender": "Male",
"Dob": "2022-02-04",
"Email": "lsngldfsng#gmail.com",
"Tel": "9958111111",
"Hobbies": [
"Coding"
]
},
{
"U_Id": "d7e5b305-4604-4831-b168-96136a7b4ea5",
"Name": "dghdghdhddh",
"Gender": "Male",
"Dob": "2022-02-04",
"Email": "lsngldfsn232g3#gmail.com",
"Tel": "8989092345",
"Hobbies": [
"Coding",
"Gaming"
]
}
]
I create the object to store using const formData = new FormData(form);.
Now when I am fetching the data to display it back into the form, I am using the following function -
const empIndex = employeeData[index];
const form = document.getElementById("form");
for(let i=0;i<form.length;i++){
console.log(form.elements[i])
console.log(empIndex[keys[i]]);
form.elements[i].value = empIndex[keys[i]];
}
const gender = empIndex.Gender;
const hobbies = empIndex.Hobbies;
form.elements[0].value = empIndex.Name;
But the issue is, the radio buttons are treated as 2 different entities and not as 1, which is why I have to individually set the name as Name and what happens is shown below-
This is how the console looks after the logs
I need to know why does the HTML not deals the radio buttons as a group and a single entity, but rather makes it seperate entities, forcing me to input values with the loop into all the form elements, meanwhile I have created a group for a reason to be able to treat it as a single entity, just like an array. An array is a group of entities, but the HTML radio button group is not a group? Anyway to go about it?
console.log("i am inside the script");
var incorrect = true;
function uuidv4() {
return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, (c) =>
(
c ^
(crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> (c / 4)))
).toString(16)
);
}
function namechecker(name) {
if (name == "" || name.length < 5 || name.length > 45) {
document.getElementById("namehidden").style.display = "contents";
} else {
document.getElementById("namehidden").style.display = "none";
incorrect = false;
}
}
function dobChecker(dob) {
if (!dob) {
document.getElementById("dobhidden").style.display = "contents";
} else {
document.getElementById("dobhidden").style.display = "none";
incorrect = false;
}
}
function emailChecker(email) {
const emailRegex =
/^([a-zA-Z0-9_\.\-])+\#(([a-zA-Z0-9\-])+\.)+([a-zA-Z0-9]{2,4})+$/;
if (!(email && emailRegex.test(email))) {
document.getElementById("emailhidden").style.display = "contents";
incorrect = true;
} else {
document.getElementById("emailhidden").style.display = "none";
incorrect = false;
}
}
function phChecker(phone) {
const phRegex = /^[6-9]\d{9}$/;
if (!phRegex.test(phone)) {
console.log("Phone number is incorrect");
document.getElementById("telhidden").style.display = "contents";
incorrect = true;
} else {
document.getElementById("telhidden").style.display = "none";
incorrect = false;
}
}
function incorrectForm(name, dob, email, tel) {
console.log(incorrect);
namechecker(name);
dobChecker(dob);
emailChecker(email);
phChecker(tel);
if (!incorrect) return false;
else return true;
}
function Init(form) {
const formData = new FormData(form);
const name = formData.get("name");
const dob = formData.get("dob");
const gender = formData.get("gender");
const email = formData.get("email");
const tel = formData.get("tel");
const markedCheckbox = document.getElementsByName("hobbies");
const hobbies = [];
for (var checkbox of markedCheckbox) {
if (checkbox.checked) {
hobbies.push(checkbox.value);
}
}
if (incorrectForm(name, dob, email, tel)) {
console.log(
"The form is incorrect. Kindly check and input correct entries."
);
alert("The Form is Incorrect. Kindly check the values and fill it correctly.")
} else {
return {
U_Id: uuidv4(),
Name: name,
Gender: gender,
Dob: dob,
Email: email,
Tel: tel,
Hobbies: hobbies,
};
}
}
const but = document.getElementById("button");
console.log(but);
but.addEventListener("click", (event) => {
event.preventDefault();
console.log("i clicked the button");
const f = document.getElementById("form");
const object = Init(f);
if (object) {
if (!localStorage.getItem("employeeData")) {
localStorage.setItem("employeeData", JSON.stringify([object]));
} else {
const existing = JSON.parse(localStorage.getItem("employeeData"));
existing.push(object);
localStorage.setItem("employeeData", JSON.stringify(existing));
}
console.log(localStorage.getItem("employeeData"));
}
// calling another script from the button if the form is correct.
if (!incorrect) {
console.log("hi i am in basic!");
var tdStyle = "border:1px solid green;min-width:110px;";
const table = document.createElement("table");
table.setAttribute("style", "table-layout: fixed; width:max-content");
const tr = document.createElement("tr");
const employeeData = JSON.parse(localStorage.getItem("employeeData"));
console.log(employeeData);
if (employeeData){
const keys = Object.keys(employeeData[0]);
for (let i = 0; i < keys.length; i++) {
const th = document.createElement("th");
th.innerText = keys[i];
th.setAttribute("style", tdStyle);
tr.appendChild(th);
}
const action = document.createElement("th");
action.innerText = "Actions";
action.setAttribute("style", tdStyle);
tr.appendChild(action);
const thead = document.createElement("thead");
thead.appendChild(tr);
table.appendChild(thead);
const tbody = document.createElement("tbody");
function btnCreator(index) {
const buttontd = document.createElement("td");
const editBtn = document.createElement("button");
editBtn.setAttribute("id" , "edit" + index);
editBtn.innerText = "Edit";
editBtn.setAttribute("style","margin-inline-end:10px");
buttontd.setAttribute("style", tdStyle);
const delBtn = document.createElement("button");
delBtn.setAttribute("id", "delete" + index);
delBtn.innerText = "Delete";
editBtn.addEventListener("click", ()=>editListener(index));
buttontd.appendChild(editBtn);
buttontd.appendChild(delBtn);
return buttontd;
}
function editListener(index){
const empIndex = employeeData[index];
const form = document.getElementById("form");
for(let i=0;i<form.length;i++){
console.log(form.elements[i])
console.log(empIndex[keys[i]]);
form.elements[i].value = empIndex[keys[i]];
}
const gender = empIndex.Gender;
const hobbies = empIndex.Hobbies;
form.elements[0].value = empIndex.Name;
document.getElementById("chkbx1").checked = false;
document.getElementById("chkbx2").checked = false;
document.getElementById("chkbx3").checked = false;
document.getElementById("rdbox1").checked = true;
document.getElementById("rdbox2").checked = false;
if (gender =="Female"){
document.getElementById("rdbox1").checked = false;
document.getElementById("rdbox2").checked = true;
}
hobbies.forEach((element)=>{
switch (element){
case "Gaming":
document.getElementById("chkbx1").checked = true;
break;
case "Coding":
document.getElementById("chkbx2").checked = true;
break;
case "Music":
document.getElementById("chkbx3").checked = true;
break;
default:
break;
}
})
}
employeeData.forEach(function (item, index, arr) {
const tr2 = document.createElement("tr");
for (let i in item) {
const td = document.createElement("td");
td.innerText = item[i];
td.setAttribute("style", "border:1px solid green; width:100%");
tr2.appendChild(td);
}
tr2.appendChild(btnCreator(index));
tbody.appendChild(tr2);
table.appendChild(tbody);
});
const basicdiv = document.getElementsByClassName("basic")[0];
basicdiv.appendChild(table);}
else{
}
});
body{
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, Cantarell, 'Open Sans', 'Helvetica Neue', sans-serif;
}
.top-div{
display: flex;
margin-top: 200px;
font-size: larger;
font-weight: bold;
justify-content: center;
align-items: center;
flex-direction: column;
width: 100%;
}
.mid-div{
display: flex;
flex-direction: column;
background-color: #1282cc;
color: black;
border-top-left-radius: 4px;
border-top-right-radius: 4px;
width: 75%;
}
.bot-div{
background-color: white;
border: solid thin #1282cc;
border-radius: 4px;
padding-bottom: 2%;
}
form{
width: 100%;
display: flex;
flex-direction: column;
}
.namelabel{
margin-top: 10px;
}
.col-25 {
float: left;
text-align: right;
width: 22%;
margin-top: 6px;
}
.col-75 {
float: right;
width: 73%;
margin-right: 2%;
}
.required{
color: red;
}
.dob ,.tel,.email{
width: 100%;
}
.vertical{
margin: 0 2.5% 0 0;
}
#button{
background-color: #1282cc;
color: white;
margin-top: 5%;
padding: 1% 2%;
border: #1282cc solid thin;
border-radius: 4px ;
}
span.items{
color:black;
padding-left: 0;
}
div span{
color: white;
font-size: medium;
font-weight: lighter;
padding:15px;
}
* {
box-sizing: border-box;
}
input[type=text] {
width: 100%;
height: 25px;
border: 1px solid #ccc;
margin: 32px 12px 12px 0;
border-bottom-left-radius: 4px;
border-bottom-right-radius: 4px;
}
input[type=radio]{
margin: 23px 12px 12px 0;
}
input[type=date] {
margin: 20px 12px 12px 0;
border: 1px solid #ccc;
height: 25px;
}
input[type=email] {
margin: 23px 12px 12px 0;
border: 1px solid #ccc;
height: 25px;
}
input[type=tel]{
margin: 23px 12px 12px 0;
border: 1px solid #ccc;
height: 25px;
}
label {
padding: 12px 12px 12px 0;
display: inline-block;
}
.hidden{
font-size: small;
color: red;
display: none;
}
.container {
background-color: white;
padding: 20px;
border: blue 1px solid;
}
/* Clear floats after the columns */
.row:after {
content: "";
display: table;
clear: both;
}
#media screen and (max-width:840px) {
.parent{
display: flex;
flex-direction: column;
}
.col-75{
margin: 0;
margin-left: 5%;
}
.col-25{
width: 100%;
margin: 0%;
padding: 12px;
text-align: left;
}
input[type=text] {
margin: 10px 12px 12px 0;
}
input[type=email] {
margin: 10px 12px 12px 0;
}
input[type=tel]{
margin: 10px 12px 12px 0;
}
input[type=radio]{
margin: 5px 5px 0 0;
}
.mf{
display: flex;
}
}
/* Adding styling for basic table */
.basic{
display: flex;
flex-direction: row;
width: 100%;
overflow-x: auto;
}
<!DOCTYPE html>
<html lang="en">
<head>
<link rel="stylesheet" href="style.css" />
<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>Employee Data</title>
<script src="basic.js" defer></script>
</head>
<body>
<div class="top-div">
<h2>Employee</h2>
<div class="mid-div">
<span>Add Employee</span>
<div class="bot-div">
<form action="" id="form">
<div class="parent">
<div class="col-25">
<label class="namelabel"> Name:</label>
</div>
<div class="col-75">
<input name="name" type="text" maxlength="45" minlength="5" placeholder="Your Name" />
<label class="hidden" id="namehidden">This field is required</label>
</div>
</div>
<div class="parent">
<div class="col-25">
<label> Gender:</label>
</div>
<div class="col-75 mf">
<div>
<input type="radio" class="radio" name="gender" value="Male" id="rdbox1" checked /><span class="items">Male</span>
</div>
<div><input type="radio" class="radio" name="gender" value="Female" id="rdbox2"/><span class="items">Female</span>
</div>
</div>
</div>
<div class="parent">
<div class="col-25">
<label> Date of Birth:</label>
</div>
<div class="col-75">
<input type="date" name="dob" class="dob" /><br>
<label class="hidden visible" id="dobhidden">This field is required</label>
</div>
</div>
<div class="parent">
<div class="col-25">
<label> Email:</label>
</div>
<div class="col-75">
<input type="email" placeholder="Enter Email" name="email" class="email" />
<br>
<label class="hidden" id="emailhidden">This field is required</label>
</div>
</div>
<div class="parent">
<div class="col-25">
<label> Phone:</label>
</div>
<div class="col-75">
<input type="tel" placeholder="Enter phone" name="tel" class="tel" />
<br>
<label class="hidden" id="telhidden">This field is incorrect</label>
</div>
</div>
<div class="parent">
<div class="col-25">
<label class="padding"> Hobbies:</label>
</div>
<div class="col-75 vertical" name="hobbies">
<input class="chkbox" type="checkbox" name="hobbies" value="Gaming" id="chkbx1" /><span
class="items">Gaming</span> <br>
<input class="chkbox" type="checkbox" name="hobbies" value="Coding" id="chkbx2" /><span
class="items">Coding</span> <br>
<input class="chkbox" type="checkbox" name="hobbies" value="Music" id="chkbx3" /><span
class="items">Music</span> <br>
</div>
</div>
<div>
<div class="col-75">
<button type="submit" id="button">Submit</button>
</div>
</div>
</form>
</div>
</div>
<h2>Basic</h2>
<div class="mid-div">
<span>Add Employee</span>
<div class="bot-div basic">
</div>
</div>
<h2>Advanced</h2>
<div class="mid-div">
<span>Add Employee</span>
<div class="bot-div">
</div>
</div>
</div>
</div>
</body>
<script src="script.js"></script>
</html>
const keys = Object.keys(employeeData[0]);
const form = document.getElementsByName("form")[0];
console.log("form in edit listener ", form);
for (let i = 0; i < form.length; i++) {
const formElement = document.forms[0].elements[i];
if (formElement.type == "radio") {
formElement.checked = formElement.value === emp.Gender;
if (!formElement.checked) {
document.forms[0].elements[i + 1].checked = true;
}
i += 1;
continue;
}
if (formElement.type == "checkbox") {
for (let j = 0; j < emp.Hobbies.length; j++) {
if (!formElement.checked) {
formElement.checked = formElement.value === emp.Hobbies[j];
}
}
}
if (formElement.type != ("checkbox" || "radio")) {
form.elements[i].value = emp[keys[i]];
if (formElement.type == "text") {
formElement.value = emp.Name;
}
}
}
This way I was able to check formElement.checked = formElement.value === emp.Gender; and set the value by using formElement.type == "radio". I was unable to think about this and it finally hit me later when I was strolling around to find a solution. This seems such a small issue but the question still remains. Why is the button group NOT A GROUP???
I have been twisting my head around on this and I can't seem to fix it.
I have not coded much, but wanting to learn. However, I am trying to make a table in which when there is no input the entire table vanishes.
As of now I have managed to get it so that it starts as vanished, and that when information is inserted into the search box the non-relevant lines dissapear. However, when all text in the search box is removed the entire table is showing. I want the table to stay hidden when there is no text that matches.
Would love to get any feedback on what I am doing wrong here.
function performSearch() {
// Declare search string
var filter = searchBox.value.toUpperCase();
// Loop through first tbody's rows
for (var rowI = 0; rowI < trs.length; rowI++) {
// define the row's cells
var tds = trs[rowI].getElementsByTagName("td");
// hide the row
trs[rowI].style.display = "none";
// loop through row cells
for (var cellI = 0; cellI < tds.length; cellI++) {
// if there's a match
if (tds[cellI].innerHTML.toUpperCase().indexOf(filter) > -1)
{
// show the row
myTable.style.display = "table";
trs[rowI].style.display = "";
// skip to the next row
continue;
}
}
}
}
// declare elements
const searchBox = document.getElementById('searchBox');
const table = document.getElementById("myTable");
const trs = table.tBodies[0].getElementsByTagName("tr");
// add event listener to search box
searchBox.addEventListener('keyup', performSearch);
* {
box-sizing: border-box;
}
#searchBox {
background-image: url('/css/searchicon.png');
background-position: 10px 10px;
background-repeat: no-repeat;
width: 30%;
font-size: 16px;
padding: 12px 20px 12px 40px;
border: 1px solid #ddd;
margin-bottom: 12px;
position: relative;
top: 50%;
left: 50%;
margin-right: -50%;
transform: translate(-50%, -50%);
}
#myTable {
border-collapse: collapse;
width: 80%;
border: 1px solid #ddd;
font-size: 18px;
position: relative;
left: 10%;
display: none;
}
#myTable th, #myTable td {
text-align: left;
padding: 12px;
}
#myTable tr {
border-bottom: 1px solid #ddd;
}
#myTable tr.header, #myTable tr:hover {
background-color: #f1f1f1;
}
#Overskrift {
width: 100%;
text-align-last: center;
font-size: 40px;
}
<input class="form-control" type="text" id="searchBox" placeholder="Search ..." onkeyup="searchTableColumns()">
<table id="myTable">
<thead>
<tr class="header">
<th onclick="sortTable(0)" style="width:35%;">Fagnavn</th>
<th onclick="sortTable(1)" style="width:21%;">LK20</th>
<th onclick="sortTable(2)" style="width:21%;">LK06</th>
<th onclick="sortTable(3)" style="width:21%;">R94</th>
</tr>
</thead>
<tbody>
<tr>
<td>Pika</td>
<td>Chu</td>
<td>Poke</td>
<td>Mon</td>
</tr>
<tr>
<td>Temporary</td>
<td>Text</td>
<td>Fields</td>
<td>Here</td>
</tr>
</tbody>
</table>
There is a simple solution for this. Just add a check to the end your performSearch function:
if (searchBox.value === ''){
table.style.display='none';
}
else {
table.style.display='table';
}
You can also check it here:
https://codepen.io/serazoltan/pen/dyZRprb
So my aim is to create a pop up modal where one could click to enter their regional school code in a text or number field to see if they are eligible for the files posted or not.
for example, if your code is 11002, you should get the recommended message else the apology message also I would like to have a button that can prompt user to go back and enter a new code if the last one is not accepted. This should all be on the same page.
Below is my code so far but I wish to display the result in a span as plain text not as in a field.
<style>
#result {
width: 100%;
}
#btn1 {
float: right;
}
</style>
<script>
function locationlookup() {
var result = document.getElementById("areacode").value;
var schooling;
if (result == 11002) {
schooling = "Great! Your school is eligible for this course";
} else if (result == 11003) {
schooling = "Great! Your school is eligible for this course";
} else if (result == 11004) {
schooling = "Your school is eligible but you need good conduct certificate";
} else {
schooling = "Sorry. we currently do not serve in your entered location";
}
document.getElementById("result").value = schooling;
}
</script>
<table align="center">
<tr>
<th>School Area code: <input type="text" name="areacode" id="areacode" >
<button onclick="locationlookup()" id="btn1">Lookup</button>
</th>
</tr>
<tr>
<th>
<input type="text" name="result" id="result" readonly></th>
<!-- I wish to change the above field to a span so no limitations. but stuff don't
work for me -->
</tr>
</table>
Maybe something like following snippet:
const input = document.querySelector("#areacode")
const span = document.querySelector("#result")
const btn = document.querySelector("#btnTryAgain")
function locationlookup() {
const result = input.value;
let schooling;
let results = [11002, 11003, 11004]
if (results.includes(Number(result))) {
schooling = "Great! Your school is eligible for this course"
} else {
schooling = "Sorry. we currently do not serve in your entered location"
btn.classList.toggle('hideBtn')
}
span.innerText = schooling;
}
function tryAgain() {
input.value = ''
span.innerText = '';
btn.classList.toggle('hideBtn')
input.focus()
}
#result {
width: 100%;
}
#btn1 {
float: right;
}
.hideBtn {
display: none;
}
<table align="center">
<tr>
<th>School Area code: <input type="text" name="areacode" id="areacode" >
<button onclick="locationlookup()" id="btn1">Lookup</button>
</th>
</tr>
<tr>
<th>
<span id="result"></span>
<button onclick="tryAgain()" id="btnTryAgain" class="hideBtn btn">Try again</button>
</th>
</tr>
</table>
So I found the below walk around to the problem which is quite handy but I will like to use that of Nikola if it finally works.
here is the code.
function openForm() {
document.getElementById("myForm").style.display = "block";
}
function closeForm() {
document.getElementById("myForm").style.display = "none";
}
function locationlookup() {
var result = document.getElementById("areacode").value;
var locality;
if (result == 11002) {
locality = "Great! Your school is eligible for this course";
} else if (result == 11003) {
locality = "Great! Your school is eligible for this course";
} else if (result == 11004) {
locality = "Your school is eligible but you need good conduct certificate and more whatever text for the coding";
} else {
locality = "Sorry. we currently do not serve in your entered location";
}
const el = document.querySelector('div[contenteditable]');
el.addEventListener('input', () => console.log(el.textContent));
el.textContent = locality;
}
/* Button used to open the contact form - fixed at the bottom of the page */
.open-button {
background-color: black;
color: white;
padding: 5px 5px;
border: none;
cursor: pointer;
opacity: 1;
}
.spanishly3 {
text-align: left;
}
.spanishly2 {
float: right;
}
.bold2 {
font-size: 16px;
}
.spanishly3:before {
content: "";
display: block;
background: url("icon.png") no-repeat;
width: 20px;
height: 20px;
float: left;
margin: 0 6px 0 0;
}
/* The popup form - hidden by default */
.form-popup {
display: none;
position: fixed;
/*bottom: 50%;*/
right: 50%;
border: 3px solid #f1f1f1;
z-index: 9;
}
/* Add styles to the form container */
.form-container {
max-width: 500px;
padding: 10px;
background-color: white;
}
/* Full-width input fields */
.form-container input[type=text], .form-container input[type=password] {
width: 100%;
padding: 15px;
margin: 5px 0 22px 0;
border: none;
background: #f1f1f1;
}
/* When the inputs get focus, do something */
.form-container input[type=text]:focus, .form-container input[type=password]:focus {
background-color: #ddd;
outline: none;
}
/* Set a style for the submit/login button */
.form-container .btn {
background-color: #04AA6D;
color: white;
padding: 16px 20px;
border: none;
cursor: pointer;
width: 100%;
margin-bottom:10px;
opacity: 0.8;
}
/* Add a red background color to the cancel button */
.form-container .cancel {
background-color: red;
}
/* Add some hover effects to buttons */
.form-container .btn:hover, .open-button:hover {
opacity: 1;
}
div[contenteditable] {
border: 1px solid black;
width: 300px;
border: none;
font-weight: bold;
}
<button class="open-button" onclick="openForm()"><div class="spanishly2"><span class="spanishly3" style="align: left;">hello</span><p><b class="bold2">Select Your Address</b></p></div></button>
<div class="form-popup" id="myForm">
<form action="/action_page.php" class="form-container">
Area code: <input type="text" name="areacode" id="areacode" placeholder="00000">
<button onclick="locationlookup()" id="btn1">Lookup</button>
<div contenteditable></div>
<p><i>or login to set/use your location</i></p>
<br>
<label for="email"><b>Email</b></label>
<input type="text" placeholder="Enter Email" name="email" required>
<label for="psw"><b>Password</b></label>
<input type="password" placeholder="Enter Password" name="psw" required>
<button type="submit" class="btn">Login</button>
<button type="button" class="btn cancel" onclick="closeForm()">Close</button>
Manage addresses
</form>
</div>
My program basically displays books and other information about it. It also should be able to delete said book from the library and also the array in which it is stored. This is where my problem lies, I can't seem to delete that exact book from the display and the array. I tried using array.pop() and deleteRow(), but they only delete from the bottom. Thanks in advance for the help.
let myLibrary = [];
function book(name, author, pages, hasRead) {
this.name = name;
this.author = author;
this.pages = pages;
this.read = hasRead;
}
const Book1 = new book('Harry Potter', 'J. K. Rowling', 322, 'Yes');
const Book2 = new book('Great Expectations', 'Charles Dickens', 234, 'Yes');
const Book3 = new book('To Kill a Mockingbird', 'Harper Lee', 312, 'No')
const Book4 = new book('The Great Gatsby', 'F Scott Fitzgerald', 421, 'Yes');
const Book5 = new book('Ulysses', 'James Joyce', 267, 'Yes');
myLibrary.push(Book1, Book2, Book3, Book4, Book5);
function tableHeader() {
var html = "<table id=myTable1>";
html += "<tr>";
html += "<th class=top1>" + 'BOOK NAME'+ "</th>";
html += "<th class=top2>" + 'AUTHOR' + "</th>";
html += "<th class=top3>" + 'PAGES' + "</th>";
html += "<th class=top4>" + 'READ?' + "</th>";
html += "</tr>";
html += "</table>";
document.getElementById("top").innerHTML = html
}
tableHeader();
function viewLibrary() {
var html = "<table id=myTable>";
for (i = 0; i < myLibrary.length; i++) {
html += "<tr>";
html += "<td>" + [i+1] + "</td>";
html += "<td class=box1>" + myLibrary[i].name + "</td>";
html += "<td class=box2>" + myLibrary[i].author + "</td>";
html += "<td class=box3>" + myLibrary[i].pages + "</td>";
html += "<td class=box4>" + myLibrary[i].read + "</td>";
html += "<td class=del>" + 'X' + "</td>";
html += "</tr>";
}
html += "</table>";
document.getElementById("box").innerHTML = html;
}
viewLibrary();
function deleteBook() {
var button = document.querySelectorAll('.del');
var table = document.getElementById('myTable');
var rowCount = table.rows.length;
for (var i = 0; i < rowCount; i++) {
button[i].addEventListener('click', function () {
table.deleteRow(this);
console.log(event);
myLibrary.pop();
})
}
}
deleteBook();
function addModal() {
var btn = document.getElementById("new-book");
var modal = document.getElementById("myModal");
var span = document.getElementsByClassName("close")[0];
btn.onclick = function () {
modal.style.display = "block";
}
span.onclick = function () {
modal.style.display = "none";
}
}
addModal();
function addBookToLibrary() {
let name = document.getElementById('name').value;
let author = document.getElementById('author').value;
let pages = document.getElementById('pages').value;
let read = document.getElementById('dropdown').value;
var submit = document.getElementById("submit");
var modal = document.getElementById("myModal");
if (name === '' || author === '' || pages === '' || read === '') {
alert("Fill out all values.")
return false;
} else {
submit.onclick = function () {
modal.style.display = "none";
}
const NewBook = new book(name, author, pages, read);
myLibrary.push(NewBook);
console.log(NewBook);
viewLibrary();
document.getElementById('name').value = '';
document.getElementById('author').value = '';
document.getElementById('pages').value = '';
document.getElementById('dropdown').value = '';
deleteBook();
}
}
let x = document.querySelectorAll('button');
x.forEach(button => {
button.addEventListener('click', () => {
let selection = button.innerHTML;
switch (selection) {
case "Submit":
addBookToLibrary();
break;
}
})
})
body {
background-color: #edc4b3;
}
/* The Modal (background) */
.modal {
display: none;
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.4);
}
/* Modal Content/Box */
.modal-content {
background-color: #eddcd2;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 40%;
}
/* The Close Button */
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
table {
margin-left: 14.5%;
margin-top: 5%;
width: 70%;
background-color: #edddd4;
border: 5px solid #8d99ae;
border-collapse: collapse;
margin-top: 2%;
}
#top {
color: #9d6b53;
}
#box {
margin-top: -1.5%;
}
.line {
color: #774936;
}
td {
padding-bottom: 10px;
padding-top: 10px;
padding-left: 10px;
}
h1 {
text-align: center;
text-transform: uppercase;
font-family: 'Notable', sans-serif;
}
h2 {
text-align: center;
text-decoration: underline;
}
#new-book {
margin-left: 79%;
background-color: #888;
cursor: pointer;
margin-top: 2%;
padding: 5px 5px;
font-weight: bold;
}
/*tr:first-child { font-weight: bold }*/
#name, #author, #pages {
width: 60%;
border: 0;
border-bottom: 1px solid black;
font-size: 1rem;
color: black;
background-color: #eddcd2;
font-family: 'Times New Roman', Times, serif;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 2px;
padding-right: 2px;
}
td {
font-family: 'Source Code Pro', monospace;
}
#author {
width: 58.5%;
}
#pages {
width: 61.3%;
}
#dropdown {
width: 28%;
background-color: #edddd4;
font-size: 17px;
cursor: pointer;
box-sizing: border-box;
margin: 0;
border: 1px solid black;
padding-top: 5px;
padding-bottom: 5px;
}
#submit {
background-color: black;
border: none;
color: white;
padding: 16px 32px;
text-decoration: none;
margin: 4px 2px;
cursor: pointer;
width: 30%;
margin-left: 35%;
}
input:focus,
select:focus,
textarea:focus,
button:focus {
outline: none;
}
.del {
color: red;
cursor: pointer;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Library</title>
<link rel="stylesheet" href="main.css">
</head>
<body>
<button id='new-book'>Add Book</button>
<section id="top"></section>
<section id="box"></section>
<div id="myModal" class="modal">
<!-- Modal content -->
<div class="modal-content">
<span class="close">×</span>
<h2>Add a new book</h2>
<label for="name">Name of the Book:</label>
<input type="text" id="name" name="fname" required><br><br>
<label for="author">Name of the Author:</label>
<input type="text" id="author" name="lname" required><br><br>
<label for="pages">Number of Pages:</label>
<input type="number" id="pages" name="pname" required><br><br>
<p>Have you read this book?</p>
<select id="dropdown" required>
<option value="" disabled selected>Select your option</option>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select><br><br>
<button id="submit">Submit</button>
</div>
</div>
<script src="main.js"></script>
</body>
</html>
I would suggest a different approach. Instead of creating your new elements through string concatenation and .innerHTML (which has performance and security implications), use the DOM API to create your new elements and then just attach an event handler to the dynamically created cells that contain the X.
See additional comments inline below:
let headers = ["name", "author", "pages", "read"];
// Get your DOM references just once, not every time
// your event handlers execute and make sure to always
// reference the DOM element, rather than a property
// of the DOM element. That way, if you ever decide
// that you need a different property value, you won't
// have to scan the DOM for the element reference again.
let box = document.getElementById("box");
var btn = document.getElementById("new-book");
var modal = document.getElementById("myModal");
let closeModal = document.querySelector("span.close");
let name = document.getElementById('name');
let author = document.getElementById('author');
let pages = document.getElementById('pages');
let read = document.getElementById('dropdown');
var submit = document.getElementById("submit");
var modal = document.getElementById("myModal");
// DO NOT USE GETELEMENTSBYCLASSNAME and especially
// pass an idex to the first element within it:
// var span = document.getElementsByClassName("close")[0];
// Read this for details: https://stackoverflow.com/questions/54952088/how-to-modify-style-to-html-elements-styled-externally-with-css-using-js/54952474#54952474
// Instead, use .querySelector()
var span = document.querySelector(".close");
// Bind the "buttons" that show/hide the modal
// to a common function that does that.
btn.addEventListener('click', showHideModal);
closeModal.addEventListener('click', showHideModal);
function showHideModal(){
// No need for if/then. Just toggle the use of
// the .hidden CSS class
modal.classList.toggle("hidden");
}
submit.addEventListener('click', addBookToLibrary);
function book(name, author, pages, hasRead) {
this.name = name;
this.author = author;
this.pages = pages;
this.read = hasRead;
}
// No need to create variables to store new book references,
// and then push them into the Array. Just put the new books
// directly into the new Array.
let myLibrary = [
new book('Harry Potter', 'J. K. Rowling', 322, 'Yes'),
new book('Great Expectations', 'Charles Dickens', 234, 'Yes'),
new book('To Kill a Mockingbird', 'Harper Lee', 312, 'No'),
new book('The Great Gatsby', 'F Scott Fitzgerald', 421, 'Yes') ,
new book('Ulysses', 'James Joyce', 267, 'Yes')
];
function makeLibrary() {
// Get rid of the prior table (if exists)
if(document.getElementById("myTable")){
document.getElementById("myTable").remove();
}
// Instead of creating concatenated strings of HTML, which gets
// messy and hard to maintain, create DOM objects and set their
// propeties.
let tbl = document.createElement("table");
tbl.id = "myTable";
for (i = 0; i < myLibrary.length; i++) {
let row = document.createElement("tr");
let numCell = document.createElement("td");
numCell.textContent = i + 1;
row.appendChild(numCell);
// Loop over the headers array to build the row cells
headers.forEach(function(header, index){
let cell = document.createElement("td");
cell.textContent = myLibrary[i][header];
cell.classList.add("box" + (index + 1));
row.appendChild(cell); // Add the cell to the row
});
let delCell = document.createElement("td");
delCell.textContent = "X";
delCell.classList.add("del");
// Because the elements are now being created as elements
// and not strings, you can set up even binding on them.
delCell.addEventListener("click", function(){
myLibrary.splice(i, 1); // Remove book from library
this.closest("tr").remove(); // Remove row
});
row.appendChild(delCell); // Add cell to row
tbl.appendChild(row); // Add row to table
box.appendChild(tbl); // Add table to section
}
}
makeLibrary();
function addBookToLibrary() {
if (name.value === '' || author.value === '' || pages.value === '' || read.value === '') {
alert("Fill out all values.")
return false;
} else {
myLibrary.push(new book(name.value, author.value, pages.value, read.value));
makeLibrary();
name.value = '';
author.value = '';
pages.value = '';
dropdown.value = '';
showHideModal();
}
}
body {
background-color: #edc4b3;
}
/* Added classes */
h1.addBook { font-size: 1em; }
.hidden { display:none; }
/* The Modal (background) */
.modal {
position: fixed;
z-index: 1;
left: 0;
top: 0;
width: 100%;
height: 100%;
overflow: auto;
background-color: rgb(0, 0, 0);
background-color: rgba(0, 0, 0, 0.4);
}
/* Modal Content/Box */
.modal-content {
background-color: #eddcd2;
margin: 15% auto;
padding: 20px;
border: 1px solid #888;
width: 40%;
}
/* The Close Button */
.close {
color: #aaa;
float: right;
font-size: 28px;
font-weight: bold;
}
.close:hover,
.close:focus {
color: black;
text-decoration: none;
cursor: pointer;
}
table {
margin-left: 14.5%;
margin-top: 5%;
width: 70%;
background-color: #edddd4;
border: 5px solid #8d99ae;
border-collapse: collapse;
margin-top: 2%;
}
#top {
color: #9d6b53;
}
#box {
margin-top: -1.5%;
}
.line {
color: #774936;
}
td {
padding-bottom: 10px;
padding-top: 10px;
padding-left: 10px;
}
h1 {
text-align: center;
text-transform: uppercase;
font-family: 'Notable', sans-serif;
}
h2 {
text-align: center;
text-decoration: underline;
}
#new-book {
margin-left: 79%;
background-color: #888;
cursor: pointer;
margin-top: 2%;
padding: 5px 5px;
font-weight: bold;
}
/*tr:first-child { font-weight: bold }*/
#name, #author, #pages {
width: 60%;
border: 0;
border-bottom: 1px solid black;
font-size: 1rem;
color: black;
background-color: #eddcd2;
font-family: 'Times New Roman', Times, serif;
padding-top: 5px;
padding-bottom: 5px;
padding-left: 2px;
padding-right: 2px;
}
td {
font-family: 'Source Code Pro', monospace;
}
#author {
width: 58.5%;
}
#pages {
width: 61.3%;
}
#dropdown {
width: 28%;
background-color: #edddd4;
font-size: 17px;
cursor: pointer;
box-sizing: border-box;
margin: 0;
border: 1px solid black;
padding-top: 5px;
padding-bottom: 5px;
}
#submit {
background-color: black;
border: none;
color: white;
padding: 16px 32px;
text-decoration: none;
margin: 4px 2px;
cursor: pointer;
width: 30%;
margin-left: 35%;
}
input:focus,
select:focus,
textarea:focus,
button:focus {
outline: none;
}
.del {
color: red;
cursor: pointer;
}
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Library</title>
<link rel="stylesheet" href="main.css">
</head>
<body>
<button id='new-book'>Add Book</button>
<section id="top">
<!-- If you have static bits of HTML, don't create them
dynamically in JavaScript, go ahead and hard-code them
into the HTML. This will reduce the amount of JavaScript
and improve the speed of the page load. -->
<table id="myTable1">
<tr>
<th class="top1">BOOK NAME</th>
<th class=top2>AUTHOR</th>
<th class=top3>PAGES</th>
<th class=top4>READ?</th>
</tr>
</table>
</section>
<section id="box"></section>
<div id="myModal" class="modal hidden">
<!-- Modal content -->
<div class="modal-content">
<span class="close">×</span>
<!-- You can't have an H2 if it's not a child of an H1.
Don't choose a heading because of how it looks, pick
it because it represents the right heading level and
then style it with CSS. -->
<h1 class="addBook">Add a new book</h1>
<label for="name">Name of the Book:</label>
<input type="text" id="name" name="fname" required><br><br>
<label for="author">Name of the Author:</label>
<input type="text" id="author" name="lname" required><br><br>
<label for="pages">Number of Pages:</label>
<input type="number" id="pages" name="pname" required><br><br>
<p>Have you read this book?</p>
<select id="dropdown" required>
<option value="" disabled selected>Select your option</option>
<option value="Yes">Yes</option>
<option value="No">No</option>
</select><br><br>
<button id="submit">Submit</button>
</div>
</div>
<script src="main.js"></script>
</body>
</html>
function deleteBook() {
var button = document.querySelectorAll('.del');
var table = document.getElementById('myTable');
var rowCount = table.rows.length;
for (var i = 0; i < rowCount; i++) {
button[i].addEventListener('click', function () {
table.deleteRow(i);
// I think pop will delete only the last element.
myLibrary.splice(i, 1);
})
}
}
this in table.deleteRow(this) refers to a HTMLTableCellElement.
According to this doc : https://www.w3schools.com/jsreF/met_table_deleterow.asp
You'll need to pass an index instead.
Edit :
What about adding a data-row attribute to your rows where you put the index, and then getting this index by using element.dataset.row
E.G :
var html = "<table id=myTable1>";
html += "<tr data-row=" + $yourIndex + ">";
html += "<th class=top1>" + 'BOOK NAME'+ "</th>";
html += "<th class=top2>" + 'AUTHOR' + "</th>";
html += "<th class=top3>" + 'PAGES' + "</th>";
html += "<th class=top4>" + 'READ?' + "</th>";
html += "</tr>";
html += "</table>";
Use Splice to remove the element from the array. Use this link for your reference.
your way of explanation is a little bit vague to understand.