I want to be able to get the product that I click on. Right now I get the whole product array directly. Any tips or help?
This is what I get now when i press buy button: (GIF) https://gyazo.com/ea20d377adc802782dcf88079fd209b5
This is my JS code:
const shopContainer = document.querySelector(".shop-content");
let productTitle;
let productDescription;
let productImage;
let productPrice;
let productCategory;
let productId;
let productKey = [];
let productArray = [];
let output = "";
const url = "https://fakestoreapi.com/products";
let data = fetch(url)
.then((res) => res.json())
.then((data) => {
for (let i = 0; i < data.length; i++) {
productTitle = data[i].title;
productDescription = data[i].description;
productImage = data[i].image;
productPrice = data[i].price;
productCategory = data[i].category;
productId = data[i].id;
productArray[i] = [
productTitle,
productDescription,
productImage,
productPrice,
productCategory,
productId,
];
productKey[i] = data[i].id;
localStorage.setItem(productKey[i], JSON.stringify(productArray[i]));
}
showApi();
console.log(productArray)
});
console.log(localStorage)
function showApi() {
for (let i = 0; i < productArray.length; i++) {
output += `
<div class="product-box">
<img class="product" src="${productArray[i][2]}" alt="product image">
<h2 class="product-title">${productArray[i][0]}</h2>
<div class="bottom-box">
<span class="price">${productArray[i][3]}$</span>
<i class='bx bx-shopping-bag add-cart' id="${i}" onclick="returnKey()"></i>
</div>
</div>
`;
}
shopContainer.innerHTML = output;
console.log(productArray);
};
let knapp = document.getElementsByClassName("bx bx-shopping-bag");
console.log(knapp);
let inputCart = document.querySelector(".inputCart")
function returnKey() {
if (localStorage.length !== 0){
Object.keys(localStorage).forEach(function (key){
object = JSON.parse(localStorage.getItem(key))
completeProduct = (object)
let cartPrice = document.createElement("p");
let cartTitle = document.createElement("p");
let cartImage = document.createElement("img");
inputCart.appendChild(cartPrice);
inputCart.appendChild(cartImage);
inputCart.appendChild(cartTitle);
cartTitle.setAttribute("class", "cart-title")
cartImage.setAttribute("src", completeProduct[2]);
cartImage.setAttribute("width", "75");
cartImage.setAttribute("height", "75");
cartTitle.innerHTML = completeProduct[0];
cartPrice.innerHTML = ("$" + completeProduct[3]);
})
inputCart.innerHTML = cartTitle;
}
};
let removeBtn = document.getElementById("removebutton").addEventListener('click', clearCart);
let buyBtn = document.getElementById("buyBtn").addEventListener('click', buyCart);
function clearCart() {
removeCart = window.confirm("Are you sure you want to clear your cart?");
if (removeCart) {
inputCart.innerHTML = "";
}
}
function buyCart() {
shopMore = window.confirm("Are you finished shopping?");
if (shopMore) {
alert("Thank your for shopping at CatchShop!");
window.location.reload();
}
}
let cartIcon = document.querySelector("#cart-icon");
let cart = document.querySelector(".cart");
let closeCart = document.querySelector("#close-cart");
cartIcon.onclick = () => {
cart.classList.add("active");
};
closeCart.onclick = () => {
cart.classList.remove("active");
};
let filterBtn = document.querySelector("#filter-button");
let filterContainer = document.querySelector(".filter-container");
let closeFilter = document.querySelector("#close-filterbox");
filterBtn.onclick = () => {
filterContainer.classList.add("active");
};
closeFilter.onclick = () => {
filterContainer.classList.remove("active");
};
And this is my HTML:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="assets/css/style.css">
<link href="https://fonts.googleapis.com/css2?family=Quicksand&family=Roboto&display=swap" rel="stylesheet">
<link href='https://unpkg.com/boxicons#2.1.4/css/boxicons.min.css' rel='stylesheet'>
<link rel="icon" href="./assets/images/android-chrome-192x192.png">
<title>CatchShop</title>
</head>
<body>
<header>
<div class="nav container">
CatchShop
Contact
About us
<i class='bx bxs-shopping-bag' id="cart-icon"></i>
<div class="cart">
<img class="companylogo" src="./assets/images/android-chrome-192x192.png" alt="logo">
<h2 class="yourcart">Your Cart</h2>
<i class='bx bx-x' id="close-cart"></i>
<div class="inputCart"></div>
<i class='bx bxs-trash-alt cart-remove' id="removebutton"></i>
<button type="button" class="btn-buy" id="buyBtn">Buy now</button>
</div>
</div>
</header>
<section class="shop container">
<div class="shop-content">
</div>
</section>
<div id="showCars"></div>
<footer>
<div class="companyname">
CatchShop
<img class="footerlogo" src="./assets/images/android-chrome-192x192.png" alt="logo">
</div>
<div class="social-media">
<i class='bx bxl-twitter' id="social-media-icon"></i>
<i class='bx bxl-facebook' id="social-media-icon"></i>
<i class='bx bxl-instagram' id="social-media-icon"></i>
</div>
</footer>
<script src="./assets/js/store.js"></script>
<script src="./assets/js/main.js"></script>
</body>
</html>
I've tried to add event.target.id with no sucess.
May be if i am not wrong then you have make mistake in below function:
function showApi() {
for (let i = 0; i < productArray.length; i++) {
output += `
<div class="product-box">
<img class="product" src="${productArray[i][2]}" alt="product image">
<h2 class="product-title">${productArray[i][0]}</h2>
<div class="bottom-box">
<span class="price">${productArray[i][3]}$</span>
<i class='bx bx-shopping-bag add-cart' id="${i}" onclick="returnKey(${productArray[i][3]})"></i>
</div>
</div>
`;
}
shopContainer.innerHTML = output;
console.log(productArray);
};
I have made change in above code for to pass productID in function returnKey
function returnKey(productID) {
if (localStorage.length !== 0){
let cartTitle = document.createElement("p");
Object.keys(localStorage).forEach(function (key){
object = JSON.parse(localStorage.getItem(key))
completeProduct = (object)
if(productID == completeProduct.productId){
let cartPrice = document.createElement("p");
let cartImage = document.createElement("img");
inputCart.appendChild(cartPrice);
inputCart.appendChild(cartImage);
inputCart.appendChild(cartTitle);
cartTitle.setAttribute("class", "cart-title")
cartImage.setAttribute("src", completeProduct[2]);
cartImage.setAttribute("width", "75");
cartImage.setAttribute("height", "75");
cartTitle.innerHTML = completeProduct[0];
cartPrice.innerHTML = ("$" + completeProduct[3]);
}
});
inputCart.innerHTML = cartTitle;
}
};
As per productId record get filter & showing one record which is clicked.
Related
I am haveing problem with getting input from my website send it so node (server.js) and the value to database. I already have done database connection and it works but value of input was undefined, so i have found out that i dont know how to get the input from the webpage (store.ejs).
So if someone could help.
"I am making eshop for my self".
store.ejs
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Store</title>
<link rel="shortcut icon" type="image/x-icon" href="/images/logo.png" />
<link rel="stylesheet" href="style.css">
<script src="https://checkout.stripe.com/checkout.js" defer></script>
<script>
var stripePublicKey = '<%= stripePublicKey %>'
</script>
<script src="script.js" defer></script>
<!--<script src="../billing.js" defer></script>-->
<link rel="icon" href="/images/logo.png">
</head>
<body>
<!-- <img src="cart-logo.png" id="cart-logo" style="background-color: #eee;border-radius: 50%;"> -->
<span id="logo2">
<img src="/images/logo.png" style="border-radius: 50%; width: 100px; position: relative; right: 0%; left: 50%;">
</span>
<div id="navigator1">
<nav>
<ul>
<li><a href='store'>Store</a></li>
<li> About us</li>
<!--<li><a href='tshirtjacket.html'></a></li>-->
<!--<li><a href='other.html'></a></li>-->
<!--<li><a href=''>Other</a></li>-->
<!--<li><a href=''>Other</a></li>-->
<div class="img2">
<li><img src="/images/instagram-logo.png" id="img2"></li>
</div>
</ul>
</nav>
<div id="navigator1"></div>
<section class="container content-section">
<h1 style="text-align: center;">Store</h1>
<br>
<div></div>
<div class="shop-items">
<% items.boot.forEach(function(item){ %>
<div class="shop-item" data-item-id="<%= item.id %>">
<span class="shop-item-title"><%= item.name %></span>
<img class="shop-item-image" src="/images/<%= item.imgName %>">
<div class="shop-item-details">
<span class="shop-item-price">$<%= item.price / 100 %></span>
<span class=""><%= item.quantity%> in stock</span>
<button class="btn btn-primary shop-item-button" type="button">ADD TO CART</button>
</div>
</div>
<% }) %>
</div>
</div>
</section>
<section class="container content-section">
<h2 class="section-header">CART</h2>
<div class="cart-row">
<span class="cart-item cart-header cart-column">ITEM</span>
<span class="cart-price cart-header cart-column">PRICE</span>
<span class="cart-quantity cart-header cart-column">QUANTITY</span>
</div>
<div class="cart-items">
</div>
<div class="cart-total">
<strong class="cart-total-title">Total</strong>
<span class="cart-total-price">$0</span>
</div>
<form action="../server.js" method="POST" id="billing">
<div class="form-group" id="billing1">
<label for="state"><!--State--></label>
<input type="text" id="state" placeholder="State: " name="state">
</div>
<div class="form-group">
<label for="address"><!--Address--></label>
<input type="text" id="address" placeholder="Address: " name="address">
</div>
<div class="form-group">
<label for="exampleInputEmail1"><!--Zip code--></label>
<input type="text" id="zip" name="zip" placeholder="Zip code: ">
</div>
<button class="btn btn-primary btn-purchase" onclick="clicked()" type="button">PURCHASE</button>
</form>
</section>
</body>
</html>
server.js
require('dotenv').config()
}
const stripeSecretKey = process.env.STRIPE_SECRET_KEY
const stripePublicKey = process.env.STRIPE_PUBLIC_KEY
//console.log(stripeSecretKey, stripePublicKey)
const express = require('express')
const app = express()
const fs = require('fs')
const stripe = require('stripe')(stripeSecretKey)
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
var bodyParser = require('body-parser');
var flash = require('express-flash');
var session = require('express-session');
var mysql = require('mysql');
var http = require('http');
app.set('view engine', 'ejs')
app.set('views', path.join(__dirname, 'views'));
app.use(express.json())
app.use(express.static('public'))
app.use(logger('dev'));
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
app.use(session({
secret: '123456catr',
resave: false,
saveUninitialized: true,
cookie: { maxAge: 60000 }
}))
app.use(flash());
var con = mysql.createConnection({
host: "localhost",
user: "root",
password: "",
database: "bonekicks"
});
app.get('/store', function(req, res) {
fs.readFile('items.json', function(error, data) {
if (error) {
res.status(500).end()
} else {
res.render('store.ejs', {
stripePublicKey: stripePublicKey,
items: JSON.parse(data)
})
}
})
})
app.post('/purchase', function(req, res) {
fs.readFile('items.json', function(error, data) {
if (error) {
res.status(500).end()
} else {
const itemsJson = JSON.parse(data)
const itemsArray = itemsJson.boot
let total = 0
req.body.items.forEach(function(item){
const itemJson = itemsArray.find(function(a){
return a.id == item.id
})
total = total + itemJson.price * item.quantity
console.log(Date())
console.log("id of product: " + itemJson.id + "; quantity: " + item.quantity + " "+ total)
console.log("//////////////////////////////////////////////////////////////////////////////////")
})
stripe.charges.create({
amount: total,
source: req.body.stripeTokenId,
currency: 'usd',
}).then(function(){
console.log('Charge Succesful')
res.json({message: 'Successfully purchased items ;)'})
var state1 = req.body.state;
var address = req.body.address;
var zip = req.body.zip;
var state;
con.connect(function(err) {
if (err) throw err;
var sql = `INSERT INTO customers (c_state, c_address, c_zip) VALUES ("${state1}", "${address}", "${zip}")`;
con.query(sql, function (err, result) {
if (err) throw err;
console.log("1 record inserted, ID: " + result.insertId);
//console.log(state + " " + address + " " + zip);
});
});
}).catch(function(){
console.log('Charge Fail')
res.status(500).end()
})
}
})
})
app.listen(3000)```
and script.js whitch is used by store.ejs
and script.js whitch is used by store.ejs
if (document.readyState == 'loading') {
document.addEventListener('DOMContentLoaded', ready)
} else {
ready()
}
function ready() {
var removeCartItemButtons = document.getElementsByClassName('btn-danger')
for (var i = 0; i < removeCartItemButtons.length; i++) {
var button = removeCartItemButtons[i]
button.addEventListener('click', removeCartItem)
}
var quantityInputs = document.getElementsByClassName('cart-quantity-input')
for (var i = 0; i < quantityInputs.length; i++) {
var input = quantityInputs[i]
input.addEventListener('change', quantityChanged)
}
var addToCartButtons = document.getElementsByClassName('shop-item-button')
for (var i = 0; i < addToCartButtons.length; i++) {
var button = addToCartButtons[i]
button.addEventListener('click', addToCartClicked)
}
document.getElementsByClassName('btn-purchase')[0].addEventListener('click', purchaseClicked)
}
var stripeHandler = StripeCheckout.configure({
key: stripePublicKey,
locale: 'auto',
token: function(token) {
var items = []
var cartItemContainer = document.getElementsByClassName('cart-items')[0]
var cartRows = cartItemContainer.getElementsByClassName('cart-row')
for (var a = 0; a < cartRows.length; a++) {
var cartRow = cartRows[a]
var quantityElement = cartRow.getElementsByClassName('cart-quantity-input')[0]
var quantity = quantityElement.value
var id = cartRow.dataset.itemId
items.push({
id: id,
quantity: quantity
})
}
fetch('/purchase', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json'
},
body: JSON.stringify({
stripeTokenId: token.id,
items: items
})
}).then(function(res){
return res.json()
}).then(function(data){
alert(data.message)
var cartItems = document.getElementsByClassName('cart-items')[0]
while (cartItems.hasChildNodes()) {
cartItems.removeChild(cartItems.firstChild)
}
updateCartTotal()
}).catch(function(error){
console.error(error)
})
}
})
function purchaseClicked() {
var priceElement = document.getElementsByClassName('cart-total-price')[0]
var price = parseFloat(priceElement.innerText.replace('$', '')) * 100
stripeHandler.open({
amount: price
})
}
function removeCartItem(event) {
var buttonClicked = event.target
buttonClicked.parentElement.parentElement.remove()
updateCartTotal()
}
function quantityChanged(event) {
var input = event.target
if (isNaN(input.value) || input.value <= 0) {
input.value = 1
}
updateCartTotal()
}
function addToCartClicked(event) {
var button = event.target
var shopItem = button.parentElement.parentElement
var title = shopItem.getElementsByClassName('shop-item-title')[0].innerText
var price = shopItem.getElementsByClassName('shop-item-price')[0].innerText
var imageSrc = shopItem.getElementsByClassName('shop-item-image')[0].src
var id = shopItem.dataset.itemId
addItemToCart(title, price, imageSrc, id)
updateCartTotal()
}
function addItemToCart(title, price, imageSrc, id) {
var cartRow = document.createElement('div')
cartRow.classList.add('cart-row')
cartRow.dataset.itemId = id
var cartItems = document.getElementsByClassName('cart-items')[0]
var cartItemNames = cartItems.getElementsByClassName('cart-item-title')
for (var i = 0; i < cartItemNames.length; i++) {
if (cartItemNames[i].innerText == title) {
alert('This item is already added to the cart')
return
}
}
var cartRowContents = `
<div class="cart-item cart-column">
<img class="cart-item-image" src="${imageSrc}" width="100" height="100">
<span class="cart-item-title">${title}</span>
</div>
<span class="cart-price cart-column">${price}</span>
<div class="cart-quantity cart-column">
<input class="cart-quantity-input" type="number" value="1">
<button class="btn btn-danger" type="button">REMOVE</button>
</div>`
cartRow.innerHTML = cartRowContents
cartItems.append(cartRow)
cartRow.getElementsByClassName('btn-danger')[0].addEventListener('click', removeCartItem)
cartRow.getElementsByClassName('cart-quantity-input')[0].addEventListener('change', quantityChanged)
}
function updateCartTotal() {
var cartItemContainer = document.getElementsByClassName('cart-items')[0]
var cartRows = cartItemContainer.getElementsByClassName('cart-row')
var total = 0
for (var i = 0; i < cartRows.length; i++) {
var cartRow = cartRows[i]
var priceElement = cartRow.getElementsByClassName('cart-price')[0]
var quantityElement = cartRow.getElementsByClassName('cart-quantity-input')[0]
var price = parseFloat(priceElement.innerText.replace('$', ''))
var quantity = quantityElement.value
total = total + (price * quantity)
}
total = Math.round(total * 100) / 100
document.getElementsByClassName('cart-total-price')[0].innerText = '$' + total
}
Image of directory tree - If needed
I am trying to implement the following tags with my design.
I am using the class Tags to simply create tags within my input field, however when I initialize the library I get an error.
const ACTIVE_CLASS = "bg-light";
const VALUE_ATTRIBUTE = "data-value";
class Tags {
/**
* #param {HTMLSelectElement} selectElement
*/
constructor(selectElement) {
this.selectElement = selectElement;
this.selectElement.style.display = "none";
this.placeholder = this.getPlaceholder();
this.allowNew = selectElement.dataset.allowNew ? true : false;
// Create elements
this.holderElement = document.createElement("div");
this.containerElement = document.createElement("div");
this.dropElement = document.createElement("ul");
this.searchInput = document.createElement("input");
this.holderElement.appendChild(this.containerElement);
this.containerElement.appendChild(this.searchInput);
this.holderElement.appendChild(this.dropElement);
// insert after
this.selectElement.parentNode.insertBefore(this.holderElement, this.selectElement.nextSibling);
// Configure them
this.configureSearchInput();
this.configureHolderElement();
this.configureDropElement();
this.configureContainerElement();
this.buildSuggestions();
}
/**
* Attach to all elements matched by the selector
* #param {string} selector
*/
static init(selector = "select[multiple]") {
let list = document.querySelectorAll(selector);
for (let i = 0; i < list.length; i++) {
let el = list[i];
let inst = new Tags(el);
}
}
/**
* #returns {string}
*/
getPlaceholder() {
let firstOption = this.selectElement.querySelector("option");
if (!firstOption) {
return;
}
if (!firstOption.value) {
let placeholder = firstOption.innerText;
firstOption.remove();
return placeholder;
}
if (this.selectElement.getAttribute("placeholder")) {
return this.selectElement.getAttribute("placeholder");
}
if (this.selectElement.getAttribute("data-placeholder")) {
return this.selectElement.getAttribute("data-placeholder");
}
return "";
}
configureDropElement() {
this.dropElement.classList.add("dropdown-menu");
}
configureHolderElement() {
this.holderElement.classList.add("form-control");
this.holderElement.classList.add("dropdown");
}
configureContainerElement() {
this.containerElement.addEventListener("click", (event) => {
this.searchInput.focus();
});
// add initial values
let initialValues = this.selectElement.querySelectorAll("option[selected]");
for (let j = 0; j < initialValues.length; j++) {
let initialValue = initialValues[j];
if (!initialValue.value) {
continue;
}
this.addItem(initialValue.innerText, initialValue.value);
}
}
configureSearchInput() {
this.searchInput.type = "text";
this.searchInput.autocomplete = false;
this.searchInput.style.border = 0;
this.searchInput.style.outline = 0;
this.searchInput.style.maxWidth = "100%";
this.adjustWidth();
this.searchInput.addEventListener("input", (event) => {
this.adjustWidth();
if (this.searchInput.value.length >= 1) {
this.showSuggestions();
} else {
this.hideSuggestions();
}
});
// keypress doesn't send arrow keys
this.searchInput.addEventListener("keydown", (event) => {
if (event.code == "Enter") {
let selection = this.getActiveSelection();
if (selection) {
this.addItem(selection.innerText, selection.getAttribute(VALUE_ATTRIBUTE));
this.resetSearchInput();
this.hideSuggestions();
} else {
// We use what is typed
if (this.allowNew) {
this.addItem(this.searchInput.value);
this.resetSearchInput();
this.hideSuggestions();
}
}
event.preventDefault();
return;
}
if (event.code == "ArrowUp") {
this.moveSelectionUp();
}
if (event.code == "ArrowDown") {
this.moveSelectionDown();
}
if (event.code == "Backspace") {
if (this.searchInput.value.length == 0) {
this.removeLastItem();
this.adjustWidth();
}
}
});
}
moveSelectionUp() {
let active = this.getActiveSelection();
if (active) {
let prev = active.parentNode;
do {
prev = prev.previousSibling;
} while (prev && prev.style.display == "none");
if (!prev) {
return;
}
active.classList.remove(ACTIVE_CLASS);
prev.querySelector("a").classList.add(ACTIVE_CLASS);
}
}
moveSelectionDown() {
let active = this.getActiveSelection();
if (active) {
let next = active.parentNode;
do {
next = next.nextSibling;
} while (next && next.style.display == "none");
if (!next) {
return;
}
active.classList.remove(ACTIVE_CLASS);
next.querySelector("a").classList.add(ACTIVE_CLASS);
}
}
/**
* Adjust the field to fit its content
*/
adjustWidth() {
if (this.searchInput.value) {
this.searchInput.size = this.searchInput.value.length + 1;
} else {
// Show the placeholder only if empty
if (this.getSelectedValues().length) {
this.searchInput.placeholder = "";
this.searchInput.size = 1;
} else {
this.searchInput.size = this.placeholder.length;
this.searchInput.placeholder = this.placeholder;
}
}
}
/**
* Add suggestions from element
*/
buildSuggestions() {
let options = this.selectElement.querySelectorAll("option");
for (let i = 0; i < options.length; i++) {
let opt = options[i];
if (!opt.getAttribute("value")) {
continue;
}
let newChild = document.createElement("li");
let newChildLink = document.createElement("a");
newChild.append(newChildLink);
newChildLink.classList.add("dropdown-item");
newChildLink.setAttribute(VALUE_ATTRIBUTE, opt.getAttribute("value"));
newChildLink.setAttribute("href", "#");
newChildLink.innerText = opt.innerText;
this.dropElement.appendChild(newChild);
// Hover sets active item
newChildLink.addEventListener("mouseenter", (event) => {
this.removeActiveSelection();
newChild.querySelector("a").classList.add(ACTIVE_CLASS);
});
newChildLink.addEventListener("click", (event) => {
event.preventDefault();
this.addItem(newChildLink.innerText, newChildLink.getAttribute(VALUE_ATTRIBUTE));
this.resetSearchInput();
this.hideSuggestions();
});
}
}
resetSearchInput() {
this.searchInput.value = "";
this.adjustWidth();
}
/**
* #returns {array}
*/
getSelectedValues() {
let selected = this.selectElement.querySelectorAll("option:checked");
return Array.from(selected).map((el) => el.value);
}
/**
* The element create with buildSuggestions
*/
showSuggestions() {
if (!this.dropElement.classList.contains("show")) {
this.dropElement.classList.add("show");
}
// Position next to search input
this.dropElement.style.left = this.searchInput.offsetLeft + "px";
// Get search value
let search = this.searchInput.value.toLocaleLowerCase();
// Get current values
let values = this.getSelectedValues();
// Filter the list according to search string
let list = this.dropElement.querySelectorAll("li");
let found = false;
let firstItem = null;
for (let i = 0; i < list.length; i++) {
let item = list[i];
let text = item.innerText.toLocaleLowerCase();
let link = item.querySelector("a");
// Remove previous selection
link.classList.remove(ACTIVE_CLASS);
// Hide selected values
if (values.indexOf(link.getAttribute(VALUE_ATTRIBUTE)) != -1) {
item.style.display = "none";
continue;
}
if (text.indexOf(search) !== -1) {
item.style.display = "list-item";
found = true;
if (!firstItem) {
firstItem = item;
}
} else {
item.style.display = "none";
}
}
// Special case if nothing matches
if (!found) {
this.dropElement.classList.remove("show");
}
// Always select first item
if (firstItem) {
if (this.holderElement.classList.contains("is-invalid")) {
this.holderElement.classList.remove("is-invalid");
}
firstItem.querySelector("a").classList.add(ACTIVE_CLASS);
} else {
// No item and we don't allow new items => error
if (!this.allowNew) {
this.holderElement.classList.add("is-invalid");
}
}
}
/**
* The element create with buildSuggestions
*/
hideSuggestions(dropEl) {
if (this.dropElement.classList.contains("show")) {
this.dropElement.classList.remove("show");
}
if (this.holderElement.classList.contains("is-invalid")) {
this.holderElement.classList.remove("is-invalid");
}
}
/**
* #returns {HTMLElement}
*/
getActiveSelection() {
return this.dropElement.querySelector("a." + ACTIVE_CLASS);
}
removeActiveSelection() {
let selection = this.getActiveSelection();
if (selection) {
selection.classList.remove(ACTIVE_CLASS);
}
}
removeLastItem() {
let items = this.containerElement.querySelectorAll("span");
if (!items.length) {
return;
}
let lastItem = items[items.length - 1];
this.removeItem(lastItem.getAttribute(VALUE_ATTRIBUTE));
}
/**
* #param {string} text
* #param {string} value
*/
addItem(text, value) {
if (!value) {
value = text;
}
let span = document.createElement("span");
span.classList.add("badge");
span.classList.add("bg-primary");
span.classList.add("me-2");
span.setAttribute(VALUE_ATTRIBUTE, value);
span.innerText = text;
this.containerElement.insertBefore(span, this.searchInput);
// update select
let opt = this.selectElement.querySelector('option[value="' + value + '"]');
if (opt) {
opt.setAttribute("selected", "selected");
} else {
// we need to create a new option
opt = document.createElement("option");
opt.value = value;
opt.innerText = text;
opt.setAttribute("selected", "selected");
this.selectElement.appendChild(opt);
}
}
/**
* #param {string} value
*/
removeItem(value) {
let item = this.containerElement.querySelector("span[" + VALUE_ATTRIBUTE + '="' + value + '"]');
if (!item) {
return;
}
item.remove();
// update select
let opt = this.selectElement.querySelector('option[value="' + value + '"]');
if (opt) {
opt.removeAttribute("selected");
}
}
}
export default Tags;
import Tags
Tags.init();
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="description" content="">
<meta name="author" content="Mark Otto, Jacob Thornton, and Bootstrap contributors">
<meta name="generator" content="Hugo 0.80.0">
<title>Insider</title>
<link rel="canonical" href="">
<link href="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons#1.4.0/font/bootstrap-icons.css">
<!-- Favicons -->
<link rel="apple-touch-icon" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/apple-touch-icon.png" sizes="180x180">
<link rel="icon" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/favicon-32x32.png" sizes="32x32" type="image/png">
<link rel="icon" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/favicon-16x16.png" sizes="16x16" type="image/png">
<link rel="manifest" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/manifest.json">
<link rel="mask-icon" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/safari-pinned-tab.svg" color="#7952b3">
<link rel="icon" href="https://getbootstrap.com/docs/5.0/assets/img/favicons/favicon.ico">
<meta name="theme-color" content="#7952b3">
<!-- Custom styles for this template -->
<link href="https://unpkg.com/bootstrap-table#1.18.3/dist/bootstrap-table.min.css" rel="stylesheet">
</head>
<body>
<header class="p-3 bg-dark text-white">
<div class="container">
<div class="d-flex flex-wrap align-items-center justify-content-center justify-content-lg-start">
<ul class="nav col-12 col-lg-auto me-lg-auto mb-2 justify-content-center mb-md-0">
<li>
<button class="btn btn-outline-light" type="button" data-bs-toggle="modal" data-bs-target="#exampleModal">Check
</button>
</li>
</ul>
</div>
</div>
</header>
<main class="container pt-3">
<div class="row mt-3">
<h2>Content</h2>
</div>
</main>
<!-- Modal -->
<div class="modal fade" id="exampleModal" tabindex="-1" aria-labelledby="exampleModalLabel" aria-hidden="true">
<div class="modal-dialog modal-lg">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title" id="exampleModalLabel">Your Check</h5>
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
</div>
<div class="modal-body">
<br>
<p class="h2">Check</p>
<p>Input your symbols and we will send you all relevant information.</p>
<br>
<form>
<div class="col">
<select class="form-select" id="validationTags" multiple="" data-allow-new="true" style="display: none;">
<option value="1" selected="selected">JavaScript</option>
<option value="2">HTML5</option>
<option value="3">CSS3</option>
<option value="4">jQuery</option>
<option value="5">React</option>
<option value="6">Angular</option>
<option value="7">Vue</option>
<option value="8">Python</option>
</select>
<div class="form-control dropdown">
<div><span class="badge bg-primary me-2" data-value="1">JavaScript</span><input type="text" autocomplete="false" placeholder="" size="1" style="border: 0px; outline: 0px; max-width: 100%;">
</div>
<ul class="dropdown-menu">
<li><a class="dropdown-item" data-value="1" href="#">JavaScript</a></li>
<li><a class="dropdown-item" data-value="2" href="#">HTML5</a></li>
<li><a class="dropdown-item" data-value="3" href="#">CSS3</a></li>
<li><a class="dropdown-item" data-value="4" href="#">jQuery</a></li>
<li><a class="dropdown-item" data-value="5" href="#">React</a></li>
<li><a class="dropdown-item" data-value="6" href="#">Angular</a></li>
<li><a class="dropdown-item" data-value="7" href="#">Vue</a></li>
<li><a class="dropdown-item" data-value="8" href="#">Python</a></li>
</ul>
</div>
<div class="invalid-feedback">Please select a valid tag.</div>
</div>
<button type="submit" class="btn btn-primary">Submit</button>
</form>
</div>
</div>
</div>
</div>
<!-- Modal END -->
<footer class="text-muted py-5">
<div class="container">
<p class="mb-1">Footer</p>
</div>
</footer>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap#5.0.0-beta2/dist/js/bootstrap.bundle.min.js" integrity="sha384-b5kHyXgcpbZJO/tY9Ul7kGkf1S0CWuKcCD38l8YkeH8z8QjE0GmW1gYU5S9FOnJ0" crossorigin="anonymous"></script>
</body>
</html>
As you can see the script does not work.
To be honest I am not quite sure why. I am guessing there is a problem when initializing the Tags-class. I currently do it the following:
import Tags
Tags.init();
Any suggestions what is wrong or how to correctly call the init()-function from the Tags-class?
I appreciate your replies!
In my answer I'm assuming that your question is about how to import a class from a <script> to another <script> using ECMAScript modules, which is not very clear when reading your question.
You just have to specify type="module" on the exporting script and also the importing one, then import one file from the other with its URL.
For example if you have this web site structure:
app/
├─ lib/
│ ├─ tags.js
├─ index.js
├─ index.html
The tags.js file would contain:
class Tags {
// ...
}
export default Tags;
And index.js would contain:
import Tags from './lib/tags.js';
// ...
Here is a demo, I have used data URLs as a workaround because I can't publish JavaScript files in a StackOverflow snippet, but it works exactly the same with regular <script> tags and regular URLs:
const lib = `class Tags {
static init() {
console.log('it works!');
}
}
export default Tags;`;
const libURL = createScript(lib);
const code = `import Tags from '${libURL}';
Tags.init();`;
createScript(code);
function createScript(code) {
const url = `data:application/javascript;charset=utf-8;base64,${btoa(code)}`;
const script = document.createElement('script');
script.src = url;
script.type = 'module';
document.body.appendChild(script);
return url;
}
to initiate a es6 class you would use:
const new_object = new Tags(selectElement)
you pass selectElement into your constructor function and get a new object in return.
i don't know where you are calling this code from, if you want to call it from another file you need to define it in your export default.
this way you can use the es6 import syntax.
The error export declarations may only appear at top level of a module is already explained in #Guerric P's answer.
You are calling Tags.init(); from the same file as the definition, so if you really want that you can remove:
export default Tags;
import Tags
because it's a class definition and you are calling a static function:
Tags.init(); /* default 'select[multiple]' */
it will result in no error.
I am creating a status posting and commenting system.
It is implemented in Vanilla JavaScript. Anyone can add a post and can comment on the post.
Everything is working fine but the comment section is working on first post only.
deletion of comment and post is working fine.
I don't know what's the problem is, if anyone could help me..
Here is the HTML code
<div class="container-post" id="container-post">
<div class="create-post">
<form>
<div class="form-group">
<div class="username">
<p class="name" style="top:15px;">User Name</p>
</div>
<p class="qoutes">
<textarea style=" font-size: 15pt;" class="form-control" id="enter-post" rows="7" id="mypara" placeholder="Share Your Thoughts..."></textarea>
</p>
<div class="postbar">
<button type="button" class="btn btn-primary post-me" id="post-button"> <span id="postText">Post</span></button>
</div>
</div>
</form>
</div>
<hr class="line-bar">
<div class="allpost">
<div class="mainpost" id="post-div"></div>
</div>
Here is the JavaSCript code
showTask();
showComment();
let addPost = document.getElementById("enter-post");
let addPostBtton = document.getElementById("post-button");
addPostBtton.addEventListener("click", function () {
var addPostVal = addPost.value;
if (addPostVal.trim() != 0) {
let webtask = localStorage.getItem("localtask");
if (webtask == null) {
var taskObj = [];
}
else {
taskObj = JSON.parse(webtask);
}
taskObj.push(addPostVal);
localStorage.setItem("localtask", JSON.stringify(taskObj));
}
showTask();
});
function showTask() {
let webtask = localStorage.getItem("localtask");
if (webtask == null) {
var taskObj = [];
}
else {
taskObj = JSON.parse(webtask);
}
let htmlVal = '';
let createPost = document.getElementById("post-div");
taskObj.forEach((item, index) => {
htmlVal += `
<div class="post-class"><div class="username u-name">
<p class="name i-name">${"User Name " + index}</p>
<i class="fas fa-trash-alt" onclick="removePost(${index});"></i></button>
</div>
<hr>
<p class="quotes">
${item}
</p>
<div class="comment-section" id="comment-section">
<p class="comment-qoute">
<textarea style=" font-size: 15pt;" class="form-control commentBox" rows="3" id="mypara" placeholder="Leave a comment"></textarea>
</p>
<button class="btn btn-primary comment-btn" id="commentBtn">comment</button>
<ul class="comments" id="comments-portion">
<p></p>
</ul>
</div>
</div>
<br><br>`
});
createPost.innerHTML = htmlVal;
}
function removePost(index) {
let webtask = localStorage.getItem("localtask");
let taskObj = JSON.parse(webtask);
taskObj.splice(index, 1);
localStorage.setItem("localtask", JSON.stringify(taskObj));
showTask();
}
var commentPost = document.getElementById('mypara');
var commentBtn = document.getElementById('commentBtn');
commentBtn.addEventListener('click', function () {
var commentValue = commentPost.value;
if (commentValue.trim() != 0) {
let commentTask = localStorage.getItem("comments");
if (commentTask == null) {
var commentObj = [];
}
else {
commentObj = JSON.parse(commentTask);
}
commentObj.push(commentValue);
localStorage.setItem("comments", JSON.stringify(commentObj));
}
showComment();
});
function showComment() {
let commentsTask = localStorage.getItem("comments");
if (commentsTask == null) {
var commentObj = [];
}
else {
commentObj = JSON.parse(commentsTask);
}
let commentHTMLValue = '';
var createComment = document.getElementById("comments-portion");
commentObj.forEach((item, index) => {
commentHTMLValue += `<div class="comment-box-btn">
<p>${index + ". "}<span>${item}</span></p>
<i class="far fa-times-circle fa-2x" onclick="removeComment(${index});"></i>
</div>
`;
});
createComment.innerHTML = commentHTMLValue;
}
var deleteBtn = document.querySelector('.comment-del');
deleteBtn.addEventListener('click', () => {
});
// remove comment
function removeComment(index) {
let commentTask = localStorage.getItem("comments");
let commentObj = JSON.parse(commentTask);
commentObj.splice(index, 1);
localStorage.setItem("comments", JSON.stringify(commentObj));
showComment();
}
When you use code like:
createComment.innerHTML = commentHTMLValue;
you are completely replacing the contents of the element. Try using:
createComment.innerHTML += commentHTMLValue;
which appends new content to the end of the existing contents.
I can't do a snippet here as the use of localStorage is not allowed. Copy this block into a blank file and save it as an html file and then open that in a browser.
This is how I think you are describing your requirements and is also based on the data format in my comments. It's not pretty and needs plenty of sprucing up, but it runs.
<!DOCTYPE html>
<META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=UTF-8">
<html>
<head>
<title>Task listing</title>
<script type="text/javascript">
let taskList = [];
function checkTasks() {
let tasksList = getTasksList();
if (tasksList.length == 0) {
let newTask = prompt("Please enter a task description");
if (newTask) {
let thisIndex = getNewIndex();
let a = {"id": thisIndex, "task": newTask, "comments": []}
taskList.push(a);
saveTasksList(taskList);
}
}
displayTasks();
}
function displayTasks() {
let container = document.getElementById("tasks");
container.innerHTML = "";
let taskList = getTasksList();
taskList.forEach(function(task){
let d = document.createElement("div");
d.id = "task_" + task.id;
d.className = "commentdiv";
d.innerHTML = "<h3>" + task.task + "</h3>";
let l = document.createElement("ul");
l.id = "comments_" + task.id;
let comments = task.comments;
if (comments.length > 0) {
let commentindex = 0;
comments.forEach(function(comment) {
let c = document.createElement("li");
c.innerHTML = comment;
let cb = document.createElement("button");
cb.id = "deletecomment_" + task.id + "_" + commentindex;
cb.innerHTML = "Delete comment";
cb.onclick = function() {deleteComment(task.id, commentindex);};
c.appendChild(cb);
l.appendChild(c);
})
}
let b = document.createElement("button");
b.id = "addcomment_" + task.id;
b.onclick = function() {addComment(task.id);};
b.innerHTML = "Add comment";
d.appendChild(b);
d.appendChild(l);
container.appendChild(d);
})
}
function addComment(taskid) {
let newcomment = prompt("Enter comment");
if (newcomment) {
let tasklist = getTasksList();
let filtered = tasklist.filter(task => task.id == taskid);
if (filtered[0]) {
let thisTask = filtered[0];
thisTask.comments.push(newcomment);
let thisIndex = taskList.findIndex((task) => task.id == taskid);
taskList[thisIndex] = thisTask;
}
saveTasksList(taskList);
displayTasks();
}
}
function addNewTask() {
let newTask = prompt("Enter task description");
let taskList = getTasksList();
let lastindex = localStorage.getItem("tasksindex");
let index = getNewIndex();
let a = {"id": index, "task": newTask, "comments": []}
taskList.push(a);
saveTasksList(taskList);
displayTasks();
}
function deleteComment(taskid, commentindex) {
let tasklist = getTasksList();
let filtered = tasklist.filter(task => task.id == taskid);
// as long as there is at least one task with the taskid value, find and delete the comment
// based on the index position of the comment in the comments array
if (filtered[0]) {
let thisTask = filtered[0];
thisTask.comments.splice(commentindex, 1);
let thisIndex = taskList.findIndex((task) => task.id == taskid);
taskList[thisIndex] = thisTask;
}
saveTasksList(taskList);
displayTasks();
}
function getTasksList() {
let tasks = localStorage.getItem("tasks");
taskList = JSON.parse(tasks);
if (!taskList) {
taskList = [];
}
return taskList;
}
function saveTasksList(taskList) {
localStorage.setItem("tasks", JSON.stringify(taskList));
}
function getNewIndex() {
let lastindex = localStorage.getItem("tasksindex");
let idx = 0;
if (!lastindex) {
idx = 1;
} else {
idx = Number(lastindex) + 1;
}
localStorage.setItem("tasksindex", idx);
return idx;
}
function removeAll() {
localStorage.removeItem("tasks");
localStorage.removeItem("tasksindex");
displayTasks();
}
window.onload = checkTasks;
</script>
<style type="text/css">
.commentdiv {
border:1px solid black;
width:1000px;
padding:5px;
border-radius:5px;
}
button {
margin-left:10px;
}
h3 {
width:100%;
border-bottom: 1px dotted black;
}
ul {
list-style-type:decimal;
}
</style>
</head>
<body>
<h2>My task list <button id="addNewTaskButton" onclick="addNewTask();">Add new task</button></h2>
<hr>
<div id="tasks">
</div>
<button id="removeAll" onclick="removeAll();">Remove all tasks</button>
</body>
</html>
i am making a simple search autocomplete app which search cities and it's information.
the problem is when clicked on suggestion i want that cities information in different html element.
so my javascript code is:
let search=document.getElementById("search");
let searchlist=document.getElementById("searchlist");
search.addEventListener("input",()=>searchcities(search.value));
const searchcities=async searchtext=>{
var res= await fetch("in.json");
const cities=await res.json();
let matches=cities.filter(city=>{
const regex=new RegExp(`^${searchtext}`,'gi');
return city.city.match(regex);
});
if(searchtext.length===0){
matches=[];
searchlist.innerHTML="";
}
outputHTML(matches);
};
function outputHTML(matches){
if(matches.length>0){
const html=matches.map(match=>`
<button class="card" >
<h4>${match.city}<span class="state ">(${match.admin})</span></h4>
<small>Latitude: ${match.lat}<br>longitude:${match.lng}</small>
</button>
`).join("");
searchlist.innerHTML=html;
document.querySelector(".card").addEventListener("click",showresult)
function showresult(match){
let result=document.querySelector("#finalresult");
const show=`
<div class="result">
<h4>${match.city}<span class="state ">(match.admin})</span></h4>
<small>Latitude: ${match.lat}<br>longitude:${match.lng}</small>
</div>
`;
result.innerHTML=show;
console.log(result);
}
}
}
i want this function to work :
function showresult(match){
let result=document.querySelector("#finalresult");
const show=`
<div class="result">
<h4>${match.city}<span class="state ">(match.admin})</span></h4>
<small>Latitude: ${match.lat}<br>longitude:${match.lng}</small>
</div>
`;
result.innerHTML=show;
console.log(result);
}
}
but it is giving me undefined data. I don't know what to do .
the structure of json file is like this:
{
"city": "Mumbai",
"admin": "Maharashtra",
"country": "India",
"population_proper": "12691836",
"iso2": "IN",
"capital": "admin",
"lat": "18.987807",
"lng": "72.836447",
"population": "18978000"
}
thanks for helping.
You're making it yourself to complex for what it actually is. Have you thought about data attributes? Here's an example:
//Fetch function
const searchCities = async searchText => {
if(searchText == null) return;
let matches;
if(searchText.length < 1) matches = []; //current behaviour will set it to no matches when your removed everything from the input
else {
const res = await fetch('js/in.json');
const cities = await res.json();
matches = await cities.filter(city=>{
const regex=new RegExp(`^${searchText}`,'gi');
return city.city.match(regex);
});
}
outputHTML(matches);
};
//Inner function
const outputHTML = (matches) => {
if(matches == null) return;
let html = '<p>no matches</p>';
if(matches.length !== 0) {
html = matches.map(match => `
<button class="card" data-city="${match.city}" data-admin="${match.admin}" data-lat="${match.lat}" data-lng="${match.lng}">
<h4>${match.city}<span class="state ">(${match.admin})</span></h4>
<small>Latitude: ${match.lat}<br>longitude:${match.lng}</small>
</button>
`).join('');
}
const searchlist = document.getElementById("searchlist");
searchlist.innerHTML = html;
const cards = document.querySelectorAll(".card");
cards.forEach(card => card.addEventListener("click", showResult));
};
//Click card function
const showResult = (event) => {
const card = event.currentTarget;
const result = document.querySelector('#finalresult');
const cardData = card.dataset;
const show = `
<div class="result">
<h4>${cardData.city}<span class=""state">${cardData.admin}</span></h4>
<small>Latidude: ${cardData.lat}<br>longitude:${cardData.lng}</small>
</div>
`;
result.innerHTML = show;
};
//Setup
const setup = () => {
const search = document.getElementById("search");
search.addEventListener("input",()=>searchCities(search.value));
};
//Load
window.addEventListener('load', setup);
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Indian cities</title>
<script src="js/main.js"></script>
</head>
<body>
<div class="indian-flag">
<div class="1"></div>
<div class="2"></div>
<div class="3"></div>
</div>
<div class="head">CITIES lookup</div>
<input type="text" name="" id="search" class="input" placeholder="Enter city name...">
<div id="searchlist"></div>
<div id="finalresult"></div>
</body>
</html>
I believe using this might be the best way to go about this. Although I admittedly don't fully understand how to use this outside of an object literal.
Basically I would like modalControls.editModal() to change the text node within the specific li.list-group-item that was clicked (specifically the <i class="fa fa-pencil-square-o float-right"></i> that was clicked).
I am able to return the proper text mode in the console, but if I have more then one li.list-group-item in the document it always returns the first one.
You can see the html and javascript below, and the working code here: http://gfitzpatrickportfolio.com/practice/
HTML:
<!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" />
<title>Bootstrap + Javascript List</title>
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/css/bootstrap.min.css"
integrity="sha384-PsH8R72JQ3SOdhVi3uxftmaW6Vc51MKb0q5P2rRUpPvrszuE4W1povHYgTpBfshb"
crossorigin="anonymous" />
<link href="https://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" rel="stylesheet"
integrity="sha384-wvfXpqpZZVQGK6TAh5PVlGOfQNHSoD2xbE+QkPxCAFlNEevoEH3Sl0sibVcOQVnN"
crossorigin="anonymous">
<link rel="stylesheet" href="style.css">
</head>
<body>
<div class="container">
<div class="input-group">
<input type="text" class="rounded form-control" id="myInput" />
<span id="myButton" class="input-group-addon bg-info text-white" onClick="listActions.addItem()">ADD</span>
</div>
<ul class="list-group" id="myOutput">
</ul>
</div> <!-- .containter -->
<!--modal-->
<div id="outter-modal">
<div id="modal-content" class="input-group bg-white col-lg-4 col-sm-6 col-10">
<input type="text" class="rounded form-control" id="editInput" />
<span id="editBtn" class="input-group-addon bg-info text-white" onClick="listActions.editItem()">EDIT</span>
</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.3/umd/popper.min.js"
integrity="sha384-vFJXuSJphROIrBnz7yo7oB41mKfc8JzQZiCq4NCceLEaO4IHwicKwpJf9c9IpFgh"
crossorigin="anonymous"></script>
<script src="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta.2/js/bootstrap.min.js"
integrity="sha384-alpBpkh1PFOepccYVYDB4do5UnbKysX5WZXm3XxPqe5iKTfUKjNkCk9SaVuEZflJ"
crossorigin="anonymous"></script>
<script src="app.js"></script>
</body>
</html>
Javascript:
let myOutput = document.getElementById('myOutput');
let myInput = document.getElementById('myInput');
let listGroupItems = document.querySelectorAll('.list-group-item');
let modalContainer = document.getElementById('outter-modal');
let editInput = document.getElementById('editInput');
let listActions = {
addItem: function() {
if (myInput.value === '') {
console.log('Field is empty!');
} else {
let li = document.createElement('li');
let inputValue = document.createTextNode(myInput.value);
li.innerHTML = '<i class="fa fa-times-circle-o float-right" aria-hidden="true" onClick="listActions.removeItem(this)"></i> <i class="fa fa-pencil-square-o float-right" aria-hidden="true" onClick="modalControls.editModal(this)"></i>';
li.className = 'list-group-item';
myOutput.appendChild(li);
li.appendChild(inputValue);
}
myInput.value = '';
},
editItem: function() {
let li = document.querySelector('.list-group-item');
console.log(li.childNodes[3])
console.log(editInput.value);
editInput.value = '';
},
toggleItem: function(e) {
let selectedItem = e.target;
let checkMark = document.createElement('i');
checkMark.classList.add('fa', 'fa-check-circle', 'float-left');
if (selectedItem.classList.contains('bg-success') && selectedItem.classList.contains('list-group-item')) {
selectedItem.classList.remove('bg-success');
selectedItem.classList.remove('text-white');
let iconIndex = '';
for (let i = 0; i < selectedItem.childNodes.length; i++) {
if (selectedItem.childNodes[i].className === "fa fa-check-circle float-left") {
iconIndex = i;
}
}
selectedItem.removeChild(selectedItem.childNodes[iconIndex]);
} else if (!selectedItem.classList.contains('bg-success') && selectedItem.classList.contains('list-group-item')) {
selectedItem.classList.add('bg-success');
selectedItem.classList.add('text-white');
selectedItem.appendChild(checkMark);
}
},
removeItem: function(deleteBtn) {
//when the <i> tag is created for the X button (inside the addItem function) the onClick property passes in (this). The parameter of removeItem (item) is = to (this)
deleteBtn.parentNode.remove();
}
};
// function addItem() {
// if (myInput.value === '') {
// console.log('Field is empty!');
// } else {
// let li = document.createElement('li');
// let inputValue = document.createTextNode(myInput.value);
//
// li.innerHTML = '<i class="fa fa-times-circle-o float-right" aria-hidden="true" onClick="removeItem(this)"></i> <i class="fa fa-pencil-square-o float-right" aria-hidden="true" onClick="modalControls.editModal(this)"></i>';
// li.className = 'list-group-item';
// myOutput.appendChild(li);
// li.appendChild(inputValue);
// }
// myInput.value = '';
// }
// function editItem(item) {
// console.log(item);
// }
// function toggleItem(e) {
// let selectedItem = e.target;
// let checkMark = document.createElement('i');
// checkMark.classList.add('fa', 'fa-check-circle', 'float-left');
//
//
// if (selectedItem.classList.contains('bg-success') && selectedItem.classList.contains('list-group-item')) {
// selectedItem.classList.remove('bg-success');
// selectedItem.classList.remove('text-white');
// let iconIndex = '';
//
// for (let i = 0; i < selectedItem.childNodes.length; i++) {
// if (selectedItem.childNodes[i].className === "fa fa-check-circle float-left") {
// iconIndex = i;
// }
// }
// selectedItem.removeChild(selectedItem.childNodes[iconIndex]);
// } else if (!selectedItem.classList.contains('bg-success') && selectedItem.classList.contains('list-group-item')) {
// selectedItem.classList.add('bg-success');
// selectedItem.classList.add('text-white');
// selectedItem.appendChild(checkMark);
// }
// }
// function removeItem(deleteBtn) {
// //when the <i> tag is created for the X button (inside the addItem function) the onClick property passes in (this). The parameter of removeItem (item) is = to (this)
// deleteBtn.parentNode.remove();
// }
let modalControls = {
editModal: function() {
modalContainer.style.display = 'block';
},
closeModal: function(e) {
if(e.target === modalContainer) {
modalContainer.style.display = 'none';
}
}
};
myOutput.addEventListener('click', listActions.toggleItem);
modalContainer.addEventListener('click', modalControls.closeModal);
One way would be to store the current list item in a global variable. Something like...
var currentListItem;
let listActions = {
// ...
editItem: function () {
if (currentListItem) {
// I believe this will change only the text and not its descendant nodes (unsure)
currentListItem.nodeValue = editInput.value;
}
// ...
},
// ...
}
let modalControls = {
// when you open the modal, set the current list item
editModal: function (btn) {
currentListItem = btn.parentNode;
// ...
},
// when you close, unset the current list item
closeModal: function (e) {
currentListItem = null;
// ...
}
};
Another way can be to mark the current list item (e.g. by like adding a class edit) upon opening the modal. Upon saving i.e. editItem, you search for the <li> element with class edit using document.getSelector('li.edit'), modify it, and remove the class.
So, basically, you need to store the <li> element being edited and you can do it with the parentElement property of the element being passed to modalControls.editModal, and then, in listActions.editItem replace the value.
let currentElement; // Element being edited
let listActions = {
editItem: function() {
currentElement.innerHTML = currentElement.innerHTML.replace(currentElement.innerText, editInput.value);
editInput.value = '';
}
}
let modalControls = {
editModal: function(i) {
// *i* is *this* in *modalControls.editModal(this)*
modalContainer.style.display = 'block';
currentElement = i.parentElement;
modalContainer.getElementsByTagName('input')[0].value = currentElement.innerText;
}
}