How to initiate OnClick event for each search results items so that it render a product page with meta data of that item in Javascript - javascript

How to create a onclick event for each search results items so that it render a product page with meta data of that item. I have successfully able to filter items as per keypress. Now I want to give a click event for filtered item to open a product page. How would I do that in Javascript? Please help me figure out this.
**My HTML code**
<!-- Search form -->
<div class="container">
<div class="active-pink-4 mb-4 mt-4">
<input class="form-control form_search" type="text" placeholder="Search" aria-label="Search" id="search">
</div>
<div id="match-list" name="matchid"></div>
</div><!-- End of Search form -->
<div class="container"><!-- Strat of login container-->
<div class="row" id="viewhide"><!-- Strat of login row-->
<div class="col-md-6 d-none d-sm-block"><!--start of col login img-->
<img src="https://img.etimg.com/thumb/width-1200,height-900,imgsize-27424,resizemode-1,msid-14351710/industry/healthcare/biotech/pharmaceuticals/free-medicines-to-all-patients-in-government-hospitals-from-november.jpg">
</div><!--End of col login img-->
<div class="col-md-6 text-center fadeIn first"><!--Start col login-->
<h2>Sign In</h2>
<!-- Login Form -->
<form>
<input type="text" class="form-control" id="exampleInputEmail1" aria-describedby="emailHelp" placeholder="Username">
<input type="password" class="form-control" id="exampleInputPassword1" placeholder="Password">
<div id="formFooter">
<a class="underlineHover mb-2" href="#">Forgot Password?</a>
</div>
<input type="submit" class="btn btn-primary d-flex justify-content-center d-md-table mx-auto mb-2 btn-round" value="Login">
<h5>You don't have an account ?</h5>
<input type="button" class="btn btn-primary d-flex justify-content-center d-md-table mx-auto mb-5 btn-round" value="Register">
</form>
</div><!-- End of col login-->
</div><!-- End of login row-->
</div><!-- End of login container-->
**My Js code:**
const search = document.getElementById('search');
const matchList = document.getElementById('match-list');
// Search states.json and filter it
const searchStates = async searchText =>{
const res = await fetch('lib/json/data.json').then(response =>{
//console.log(response);
if (!response.ok) {
throw Error("Error");
}
return response.json();
}).then(data =>{
//console.log(data.item);
let states = data.item;
//console.log(states, "states");
// Get matches to current text input
let matches = states.filter(state =>{
const regex = new RegExp(`^${searchText}`, `gi`);
return state.itemName.match(regex) || state.itemMfrCode.match(regex);
});
let divhide = document.getElementById('viewhide');
if(searchText.length !== 0){
divhide.style.display = "none";
}else{
divhide.style.display = "flex";
}
//Hide all results when input is empty
if (searchText.length === 0) {
matches = [];
matchList.innerHTML = '';
}
//Hide if no results are found
if (searchText !== states) {
match = [];
matchList.innerHTML = '';
}
outputHtml(matches);
}).catch(error =>{
console.log(error);
});
};
//Show results in HTML
const outputHtml = matches => {
if (matches.length > 0) {
const html = matches.map(match => `
<div class="card card-body mb-1" id="medprod" name="selectid"
onclick="getproduct()">
<h4 style="cursor: pointer;">${match.itemName}</h4>
</div>
`).join('');
matchList.innerHTML = html;
}
}
search.addEventListener('input', () => searchStates(search.value));
//On clcik search result items function
function getproduct(){
}
**My Json structure**
{
"clientId": "1234",
"systemId": "2010",
"orderReferenceNo": "43442",
"responseCode": "0000",
"responseDescription": "Items successfully retrieved!",
"item": [
{
"itemMfrCode": "0001001",
"qnty": "00000000",
"itemName": "clinic shampoo",
"unitPk": "30ml",
"itemCategory": " ",
"itemType": "NT",
"schemeRange": "000",
"schemeOffeQty": "000",
"rateDiffFlag": "N",
"schemeHalfValueFlag": " ",
"schemeHalfValuePerc": null,
"ratePerUnit": 20.00
},
{},
}

I should have posted the answer long before. No problem, hope it helps someone in future.
const search = document.getElementById('search');
const matchList = document.getElementById('match-list');
const productLayout = document.getElementById('product_layout');
//Search filter
const searchStates = async searchText => {
const res = await
fetch('https://data.json').then(response => {
if (!response.ok) {
throw Error("Error");
}
return response.json();
}).then(data => {
console.log(data.item);
let states = data.item;
console.log(states, "states");
matchList.style.display = 'block';
// Get matches to current text input
let matches = states.filter(state => {
const regex = new RegExp(`^${searchText}`, `gi`);
return state.itemName.match(regex) ||
state.itemMfrCode.match(regex);
});
if (searchText.length !== 0) {
productLayout.style.display = 'none';
} else {
productLayout.style.display = 'block';
}
outputHtml(matches);
}).catch(error => {
console.log(error);
});
};
//Show results in HTML
const outputHtml = matches => {
if (matches.length > 0) {
//Meta data of clicked item
//Keep adding
//${match.itemId},${match.itemRate},${match.itemColor} to the list.
const html = matches.map(match => `
<li id="${match.itemMfrCode}">${match.itemName}</li>
`).join('');
matchList.innerHTML = html;
}
}
search.addEventListener('input', () => searchStates(search.value));
/*OnClick filtered items*/
matchList.addEventListener('click', function(e) {
var target = e.target;
while (target && target.parentNode !== matchList) {
target = target.parentNode;
if (!target) {
return;
}
}
if (e.target.tagName === 'LI') {
//Get selected product name
let liInnerText = e.target.innerText;
//Store prod name in localStorage
localStorage.setItem('liText', liInnerText);
//Insert selected item in input text field
search.value = liInnerText;
//Hide search dropdown after click event
matchList.style.display = 'none';
/*View product layout*/
productLayout.style.display = 'block';
//Get product name from localStorage
var selectedName = localStorage.getItem('liText');
//Dispaly product name in HTML page
document.getElementById('prod_name').innerHTML =
selectedName;
}
});
#match-list {
display: none;
}
#product_layout {
display: none;
}
<!-- Search form -->
<div class="container" id="search_layout">
<div class="active-pink-4 mb-2 mt-4">
<input class="form-control form_search" type="text" placeholder="Search" aria-label="Search" id="search" value="" autocomplete="off" onfocus="this.value=''">
</div>
<ul id="match-list" name="matchid"></ul>
</div>
<!-- End of Search form -->
<!--Product details-->
<div class="container-fluid" id="product_layout">
<div>
<p id="prod_name"></p>
</div>

Related

How to save an image (input type="file") into the local storage and display it back onload of a page in javaScript

I have an input type file and when I click, it will select a particular image, likewise some other input type text which i have to use to collect data from the user and I am as well having a button to set the data into the localStorage once the button is clicked.
Onload of the page, I want the information on the localStorage (productImg, productName, productOldPrice, productCategory, productNewPrice, productSavePrice) to display on the browser.
Note: Every other information are displaying except the productImg which is why am asking this question.
What I wanted to archive is a way of setting each product image into the localStorage and when displaying it on the browser, each product image should be display on the designated place.
<button id="adminSponsorPush" class="btn btn-lg btn-success " style="width: 30%;" onclick="text()">Sponsored Products</button>
<input type="file" id="adminDealImg">
<input type="text" name="" id="adminDealName" placeholder="Product Name">
<input type="text" name="" id="adminOldPrice" placeholder="deals Old Price">
<input type="text" name="" id="adminNewPrice" placeholder="deals new Price">
<button type="button" onclick="setIt()" class="btn btn-primary">Understood</button>
<div id="todaysDeal" class="d-flex flex-wrap w-100 gap-3 p-2 border border-danger border-2"></div>
This is the JavaScript code that set the data into the localStorage
let allProducts = [];
if (localStorage.companyProduct) {
allProducts = JSON.parse(localStorage.getItem("companyProduct"));
}
text = () => {
let products = {
firstName: "",
lastName: "",
email: "",
phoneNumber: "",
password: "",
topDeal: [],
sponsorProduct: [],
recommendedProduct: [],
inspiredProduct: [],
laptops: [],
smartPhone: [],
healthBeauty: [],
groceries: [],
videoGames: [],
mobileAccessories: [],
homeFurnishings: [],
fitnessToolsEquipment: [],
kidsWearAccessories: [],
topDealOnTelevision: [],
};
allProducts.push(products);
localStorage.setItem("companyProduct", JSON.stringify(allProducts));
};
setIt = () => {
for (let index = 0; index < allProducts.length; index++) {
let topDealProduct = {
productImg: adminDealImg.value,
productName: adminDealName.value,
productOldPrice: adminOldPrice.value,
productCategory: `product`,
productNewPrice: adminNewPrice.value,
productSavePrice: `You save ₦${adminOldPrice.value - adminNewPrice.value}`,
};
allProducts[index].topDeal.push(topDealProduct);
localStorage.setItem("companyProduct", JSON.stringify(allProducts));
localStorage.setItem("currentUserIndex", index);
}
};
This is the javaScript code that will display the information into the browser when the page is load
currentProductIndex = localStorage.getItem("currentUserIndex");
displayProducts = () => {
todaysDeal.innerHTML = "";
eachTopDealProduct = allProducts[currentProductIndex].topDeal;
for (let index = 0; index < eachTopDealProduct.length; index++) {
todaysDeal.innerHTML += `
<div onclick="topDealProductPage(${index})" class="d-flex p-3 shadow each-todays-deal gap-3"
style="width: 32.5%; height: 120px; cursor: pointer;"
>
<img src="${eachTopDealProduct[index].productImg}" alt="" id="dealsImg"/>
<div class="d-flex flex-column gap-3">
<div class="text-capitalize" id="dealsProductName">${eachTopDealProduct[index].productName}</div>
<div class="">
<div class="d-flex gap-2">
<div class="fw-bold fs-4" id="dealsPrice">₦${eachTopDealProduct[index].productNewPrice}</div>
<div class="fw-bold fs-6 my-auto text-decoration-line-through text-secondary" id="dealsPrice">₦${eachTopDealProduct[index].productOldPrice}</div>
</div>
<div class="fw-bold" style="font-size: 12px; color: #33B27B;" id="dealsSave">${eachTopDealProduct[index].productSavePrice}</div>
</div>
</div>
</div>
`;
}
};
Get file data from onChange callback and transfer it to base64, then set base64 to LocalStorage.
<input type="file" id="adminDealImg">
<img src="" id="img" alt="">
<script>
if(localStorage.getItem('img-BASE64')){
document.querySelector('#img').src=localStorage.getItem('img-BASE64')
}
function getBase64(file) {
return new Promise((resolve,reject)=>{
var reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function () {
resolve(reader.result)
};
reader.onerror = reject
})
}
document.querySelector('#adminDealImg').addEventListener('change', async(e)=>{
const data = await getBase64(e.target.files[0])
localStorage.setItem('img-BASE64', data)
})
</script>
After you have changed the question.
Set img data to localStorage is different from normal data.
// error here
productImg: adminDealImg.value,
you can set image base64 data as a unique key and get it by this key as identity, maybe email ?
LocalStorage.setItem(img-Base64-${email}, 'sth base64')
Please click LIKE button. Orz....

How to transfer image upload from form to backend upload?

I managed to upload an image in form, but i want to save it to backend and then when i call it again using frontend i will b able to save a picture
function code :
addFilm: (title, description, release_year, language_id, rental_duration, rental_rate, length, replacement_cost, rating, special_features, category_id, actors, store_id, callback) => { //1.(1 ~ 3 are places to change code )
var conn = db.getConnection(); // GET CONNECTION TO DB
conn.connect((err) => {
if (err) {
console.log(err);
return callback(err, null);
} else {
console.log('Connected Successfully!');
var SQLstatement = //use backtick to go onto next line
// first insert into film table
`insert into film (title,description,release_year,language_id,rental_duration,rental_rate,length,replacement_cost,rating,special_features)
Values(?,?,?,?,?,?,?,?,?,?)`; // 2.
conn.query(SQLstatement, [title, description, release_year, language_id, rental_duration, rental_rate, length, replacement_cost, rating, special_features], (error, result_id) => { //3.
if (error) {
console.log(error);
return callback(error, null);
}
else {
// second insert into film_category table
var SQLstatement = `insert into film_category (film_id,category_id) Values (?,?)`
conn.query(SQLstatement, [result_id.insertId, category_id], (error, result) => {
if (error) {
console.log(error);
return callback(error, null);
}
else {
console.log(result);
// neeed check actor
console.log(actors);
var SQLstatement = ''
values = []
// add a new actor id with the same film id to the film_actor table
for (var k = 0; k < actors.length; k++) {
if (k == actors.length - 1) {
SQLstatement += `(?,?)`
}
else {
SQLstatement += `(?,?),`
}
// console.log(actors[k])
values.push(actors[k])
values.push(result_id.insertId)
}
var finalSQLstatement = `insert into film_actor (actor_id,film_id) Values ` + SQLstatement
conn.query(finalSQLstatement, values, (error, result) => {
if (error) {
console.log(error);
return callback(error, null);
}
})
console.log(result_id.insertId);
var SQLstatement = //use backtick to go onto next line
// last insert into inventory with same film_id and store_id
`insert into inventory(film_id,store_id) Values(?,?)`; // 2.
conn.query(SQLstatement, [result_id.insertId, store_id], (error, result) => { //3.
conn.end();
if (error) {
console.log(error);
return callback(error, null);
}
else {
console.log(result);
return callback(null, result.insertId);
}
});
}
})
// });
}
});
}
});
},
app.get():
app.get('/view/:filmid',function(req, res){
var filmid = req.params.filmid;
actorDB.getDetails(filmid, function(err, result){
if(!err){
console.log(result);
res.send(result);
}else{
res.status(500).send("Some error");
}
});
});
index.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>Customer</title>
<link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css"
integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
<div class="container">
<nav class="nav">
<a class="nav-link" href="/">Home</a>
<a class="nav-link" href="/users/">All Users</a>
</nav>
<h1>Register a new DVD</h1>
<form id="register-form">
<div class="form-group">
<div class="file-upload w-100">
<form class="image-upload-wrap d-flex justify-content-center align-items-center"
style="height: 240px">
<input class="file-upload-input" type="file" onchange="readImage(this);" accept="image/*"
id="imageFile" />
<div class="drag-text w-100 d-flex flex-column justify-content-center align-items-center">
<div id="imageErr" class="text-danger d-none">
Invalid Image
</div>
<h3>Drag photo here</h3>
<p>— or —</p>
<button class="btn bg-secondary text-white font-weight-bold text-center" type="button"
style="white-space: nowrap; z-index: 1055" id="addImage"
onclick="$('.file-upload-input').trigger( 'click' )">
Choose photo to upload
</button>
</div>
</form>
<div class="file-upload-content">
<img class="file-upload-image" style="border: 1px black solid" src="#" alt="your image"
id="imgPreview" />
</div>
</div>
</div>
<div class="form-group">
<label for="title">title:</label>
<input type="text" class="form-control" id="title" required>
</div>
<div class="form-group">
<label for="description">Description:</label>
<input type="text" class="form-control" id="description" required>
</div>
<div class="form-group">
<label for="release">Release:</label>
<input type="text" class="form-control" id="release" required>
</div>
<div class="form-group">
<label for="lang">Language_id:</label>
<input type="text" class="form-control" id="lang" required>
</div>
<div class="form-group">
<label for="rental_duration">Rental Duration:</label>
<input type="text" class="form-control" id="rental_duration" required>
</div>
<div class="form-group">
<label for="rental_rate">Rental rate:</label>
<input type="text" class="form-control" id="rental_rate" required>
</div>
<div class="form-group">
<label for="length">Length:</label>
<input type="text" class="form-control" id="length" required>
</div>
<div class="form-group">
<label for="replacement_cost">Replacement Cost:</label>
<input type="text" class="form-control" id="replacement_cost" required>
</div>
<div class="form-group">
<label for="rating">Rating:</label>
<input type="text" class="form-control" id="rating" required>
</div>
<div class="form-group">
<label for="special_features">Special Features:</label>
<input type="text" class="form-control" id="special_features" required>
</div>
<div class="form-group">
<label for="category_id">Category ID:</label>
<input type="text" class="form-control" id="category_id" required>
</div>
<div class="form-group">
<label for="actors">Actors:</label>
<input type="text" class="form-control" id="actors" required>
</div>
<div class="form-group">
<label for="store_id">Store_id:</label>
<input type="text" class="form-control" id="store_id" required>
</div>
<button type="submit" class="btn btn-primary">Register</button>
<button type="reset" class="btn btn-primary ml-5">Reset</button>
<button type="button" class="btn btn-primary ml-5" id="Logout">Log Out</button>
<!-- <input type="reset" value="Reset"> -->
</form>
</div>
<script src="https://code.jquery.com/jquery-3.3.1.min.js"
integrity="sha256-FgpCb/KJQlLNfOu91ta32o/NMZxltwRo8QtmkMRdAu8=" crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.7/umd/popper.min.js"
integrity="sha384-UO2eT0CpHqdSJQ6hJty5KVphtPhzWj9WO1clHTMGa3JDZwrnQq4sF86dIHNDz0W1"
crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/js/bootstrap.min.js"
integrity="sha384-JjSmVgyd0p3pXB1rRibZUAYoIIy6OrQ6VrjIEaFf/nJGzIxFDsf4x0xIM+B07jRM"
crossorigin="anonymous"></script>
<script src="https://unpkg.com/axios/dist/axios.min.js"></script>
<script>
const baseUrl = "http://localhost:8081";
const token = localStorage.getItem("token");
const loggedInUserID = parseInt(localStorage.getItem("loggedInUserID"));
console.log(token, loggedInUserID)
function readImage(fileInput) {
if (fileInput.files && fileInput.files[0]) {
var imgReader = new FileReader();
imgReader.onload = function (event) {
var wrap = document.querySelector(".image-upload-wrap");
if (wrap) {
wrap.classList.add("d-none");
wrap.classList.remove("d-flex");
}
var imgData = event.target.result.split(',')[1];
var postData = { image: imgData };
fetch('/upload-image.php', {
method: 'POST',
body: JSON.stringify(postData),
headers: { 'Content-Type': 'application/json' }
})
.then(response => response.json())
.then(data => {
console.log('Success:', data);
})
.catch(error => {
console.error('Error:', error);
});
document.getElementById("addImage").style.display = "none";
var imgPreview = document.getElementById("imgPreview");
imgPreview.src = event.target.result;
var content = document.querySelector(".file-upload-content");
content.classList.add("d-flex", "justify-content-center", "align-items-center");
content.classList.remove("d-none");
var btnSave = document.getElementById("save");
if (btnSave.classList.contains("btn-danger")) {
btnSave.classList.toggle("btn-danger");
btnSave.classList.add("btn-primary");
btnSave.innerHTML = "Save as promo picture";
}
};
imgReader.readAsDataURL(fileInput.files[0]);
} else {
removeUpload();
}
}
if (token === null || isNaN(loggedInUserID)) {
window.location.href = "http://localhost:3001/home";
} else {
$("#register-form").submit((event) => {
// prevent page reload
event.preventDefault();
const title = $("#title").val();
const description = $("#description").val();
const release = $("#release").val();
const lang = $("#lang").val();
const rental_duration = $("#rental_duration").val();
const rental_rate = $("#rental_rate").val();
const length = $("#length").val();
const replacement_cost = $("#replacement_cost").val();
const rating = $("#rating").val();
const feature = $("#special_features").val();
const category_id = $("#category_id").val();
const actors = $("#actors").val();
const store_id = $("#store_id").val();
const requestBody = {
title: title,
description: description,
release_year: release,
language_id: lang,
rental_duration: rental_duration,
rental_rate: rental_rate,
length: length,
replacement_cost: replacement_cost,
rating: rating,
special_features: feature,
category_id: category_id,
actors: actors,
store_id: store_id
};
let token = localStorage.getItem("token");
console.log(requestBody);
axios.post(`${baseUrl}/film`, requestBody, { headers: { "Authorization": "Bearer " + token } })
.then((response) => {
console.log(requestBody)
window.location.href = "http://localhost:3001/home";
})
.catch((error) => {
console.log(error);
if (error.response.status === 400) {
alert("Validation failed");
} else {
alert("Something unexpected went wrong.");
}
});
});
$("#Logout").click(function () {
window.localStorage.clear();
localStorage.removeItem("token");
localStorage.removeItem("loggedInUserID");
window.location.assign("http://localhost:3001/login");
});
}
</script>
</body>
</html>
I need help in parsing the data, even now as i try to submit the form it says Cannot read properties of null (reading 'classList')
at imgReader.onload.

how to dispatch form value to store and then map over store to make ul list

how can I pass value from form into store and then display dynamically a list of those input items? I am trying to make a shopping list which would be passed via form and then displayed below in ul list below.
collectRefs() {
this.form = this.rootElement.querySelector("form");
this.shopList = this.rootElement.querySelector("#shop-list"); }
applyHandlers() {
const store = createStore(rootReducers);
store.subscribe(() => {
this.shopList.innerText = `${store.getState().addProduct}`
// {.map((value, index) => <li key={index}>{value}</li>)}
console.log("stan przy subscribe " +store.getState().addProduct)
});
this.form.addEventListener('click', () => {
store.dispatch(addProduct(this.form.value))
console.log("to jest wynik " + `${store.getState().addProduct}`)
});
}
createUI(rootElement) {
this.rootElement = rootElement;
this.rootElement.innerHTML = `
<div class="card-header">Lista zakupów</div>
<div class="card-body">
<form>
<div class="input-group mb-3">
<input type="text" class="form-control" placeholder="Produkt..." />
<div class="input-group-append">
<button class="btn btn-outline-primary" type="button" id="shop-add">Dodaj</button>
</div>
</div>
</form>
<ul class="list-group mt-3" id="shop-list">
</ul>
</div>
`;
}
REDUCER:
const initState = [];
function addProduct(state = initState, action) {
switch (action.type) {
case ADD_PRODUCT:
return [...state, action.payload]
default:
return state;
}
}

is there a way to add a textarea to function with a floating label in this case?

I have a simple for with 3 fields using vue.js, I am setting up "floating labels" on focus, as of now I have the inputs working nicely adding and removing class "active" as expected. When I try to add "textarea" my app is breaking and returning "cannot read value of null", is there a way to add the textarea as the inputs are setup?
html:
<form #submit.prevent="submitForm()">
<div class="form-group">
<div id="floatWrapper" class="float-wrapper">
<label for="floatField">Enter Your Name</label>
<input
id="floatField"
v-model="contact_name"
type="text"
class="form-control form-control--email"
#input="$v.contact_name.$touch"
/>
</div>
<p v-if="$v.contact_name.$dirty">
<span v-if="!$v.contact_name.required" class="form__alert">
Please enter your name.
</span>
</p>
<div id="floatWrapper" class="float-wrapper">
<label for="floatField">Enter Your Email</label>
<input
v-model="contact_email"
type="email"
class="form-control form-control--email"
/>
</div>
<p v-if="$v.contact_email.$dirty">
<span v-if="!$v.contact_email.required" class="form__alert">
Email is required.
</span>
<span v-if="!$v.contact_email.email" class="form__alert">
Please enter a valid email
</span>
</p>
<div id="floatWrapper" class="float-wrapper">
<label for="floatField">Enter Your Message</label>
<textarea
v-model="contact_message"
class="form-control form-control--textarea"
rows="5"
/>
</div>
<p v-if="$v.contact_message.$dirty">
<span
v-if="!$v.contact_message.required"
class="form__alert"
>
Message must be over 10 characters
</span>
</p>
</div>
<button
type="submit"
data-cursor="hover"
class="btn btn-primary"
>
Send Message
<font-awesome-icon far icon="arrow-right" />
</button>
</form>
js:
mounted() {
const labelFloating = (() => {
const isFocus = (e) => {
const target = e.target
target.parentNode.classList.add('active')
}
const isBlur = (e) => {
const target = e.target
if (!target.value) {
target.parentNode.classList.remove('active')
}
}
const bindEvents = (element) => {
const field = element.querySelector('input')
field.addEventListener('focus', isFocus)
field.addEventListener('blur', isBlur)
const text = element.querySelector('textarea')
text.addEventListener('focus', isFocus)
text.addEventListener('blur', isBlur)
}
const initialize = () => {
const floatWraps = document.querySelectorAll('.float-wrapper')
floatWraps.forEach((element) => {
if (element.querySelector('input').value) {
element.classList.add('active')
} if (element.querySelector('textarea').value) {
element.classList.add('active')
}
bindEvents(element)
})
}
return {
init,
}
})()
labelFloating.init()
},
The if (element.querySelector('input').value) { will throw that error because you're chaining .value off the selector, but it doesn't exist and returns null. try this instead:
const selector = element.querySelector('input') || element.querySelector('textarea')
if (selector && selector.value) {
element.classList.add('active')
bindEvents(element)
}
And use the same refactor for the bindEvents method:
const bindEvents = (element) => {
const field = element.querySelector('input') || element.querySelector('textrea')
field.addEventListener('focus', isFocus)
field.addEventListener('blur', isBlur)
}

Dynamic add field using nested accordion

Good Day!
I'm working on my project right now and I need to dynamically add form when button click. I have a nested accordion and inside the accordion is ng-select. To make it clear this is my code
<div class="box box-default" *ngFor="let form of forms; let form_array_index = index">
<div class="box-header with-border text-center">
<h3 class="box-title">
<div class="row">
<div class="col-md-4">
<select2 id="segment" name="segment"
[data]="add_segment"
[width]="293"
[value]="segment_value"
(valueChanged)="changedSegment($event, form_array_index)"
required>
</select2>
</div>
</div>
</h3>
<div class="box-tools pull-right">
</div>
</div>
<div class="box-body">
<div class="row">
<div class="col-md-2">
<label for="category">Values:</label>
<select2 id="category" name="category"
[options]="options"
[data]="add_category"
[width]="293"
[value]="category_value"
(valueChanged)="changedCategory($event, form_array_index)"
required>
</select2>
</div>
</div>
<div class="box-header with-border text-center" *ngIf="cat_value">
<div class="panel panel-default">
<div class="panel-heading">
<h5 class="panel-title">
<a data-toggle="collapse" data-parent="#accordion1" href="#{{ category_current[form_array_index] }}">{{collection_category[form_array_index].category}}
</a>
</h5>
</div>
<div id="{{ category_current[form_array_index] }}" class="panel-collapse collapse">
<div class="panel-body">
<div class="panel-body">
<button class="btn btn-success btn-xs pull-left" (click)="addQuestions()">Add Question</button>
<div class="row" >
<select2 *ngIf="query" id="question" name="question"
[data]="add_question"
[width]="293"
[value]="question_value"
(valueChanged)="changedQuestion($event)"
required>
</select2>
</div>
<button class="btn btn-success btn-xs pull-left" (click)="addSubCat()">Add Sub Category</button>
<div class="row" >
<select2 *ngIf="subcat" id="subcategory" name="subcategory"
[options]="options"
[data]="add_subcategory"
[width]="293"
[value]="subcategory_value"
(valueChanged)="changedSubcategory($event, form_array_index)"
required>
</select2>
</div>
<div class="panel-group" id="accordion21" *ngIf="subcat">
<ul class="list-group">
<li class="list-group-item" >
<div class="panel">
<a data-toggle="collapse" data-parent="#accordion21" href="#{{ subcategory_current }}" >
<strong>{{ get_subcategory }} </strong>
</a>
<div id="{{subcategory_current}}" class="panel-collapse collapse">
<div class="panel-body">
<label for="question">Question:</label>
<select2 id="question" name="question"
[data]="add_question"
[width]="293"
[value]="question_value"
(valueChanged)="changedQuestion($event)"
required>
</select2> <br>
</div>
</div>
</div>
</li>
</ul>
</div>
</div>
</div></div>
</div>
<div class="box-tools pull-right">
</div>
</div>
</div>
This means in SEGMENT it can have multiple CATEGORY and inside category it can have a question or they they Choose SUB CATEGORY and they have to choose a question
This is my component.ts
public collection_category = [];
public collection_subcategory = [];
addSegment(){
this._q_service.addSegment().
subscribe(
data => {
this.add_segment = Array.from(data);
let id = 0;
let text = 'Select Segment';
this.add_segment.unshift({id,text});
// this.segment_value = [];
this.segment_current = this.segment_value;
},
err => console.error(err)
);
}
changedSegment(data: any, form_array_index: any) {
this.segment_current = data.value;
if(this.segment_current.length > 0){
for (let i = 0; i < this.add_segment.length; ++i) {
if (this.add_segment[i].id == this.category_current) {
this.collection_category[form_array_index].segment = this.add_segment[i].text;
}
}
}
console.log('segment', this.collection_category);
}
addCategory(){
this._q_service.addCategory().
subscribe(
data => {
this.add_category = Array.from(data);
this.category_value = [];
this.options = {
multiple: true
}
let id = 0;
let text = 'Select Category';
this.add_category.unshift({id,text});
this.category_value = [];
// this.category_current.push(this.category_value);
// console.log(this.category_current);
},
err => console.error(err)
);
}
changedCategory(data: any, form_array_index: any ) {
this.category_current = data.value;
if(this.category_current.length > 0){
let len = this.add_category.length;
for (let i = 0; i < len; ++i) {
if (this.add_category[i].id == this.category_current) {
this.get_category = this.add_category[i].text;
this.collection_category[form_array_index].category = this.add_category[i].text;
}
}
this.cat_value = true;
}
console.log(this.collection_category);
this.addSubCategory();
this.addQuestion();
}
addSubCategory(){
this._q_service.addSubCategory().
subscribe(
data => {
this.add_subcategory = Array.from(data);
this.subcategory_value = [];
this.options = {
multiple: true
}
let id = 0;
let text = 'Select Sub Category';
this.add_subcategory.unshift({id,text});
this.subcategory_value = [];
this.subcategory_current = this.subcategory_value;
},
err => console.error(err)
);
}
changedSubcategory( data: any, form_array_index: any ) {
this.subcategory_current = data.value;
if(this.subcategory_current.length > 0){
let len = this.add_subcategory.length;
for (let i = 0; i < len; ++i) {
if (this.add_subcategory[i].id == this.subcategory_current) {
this.get_subcategory = this.add_subcategory[i].text;
this.collection_category[form_array_index].subcategory = this.add_subcategory[i].text;
// this.collection_subcategory[form_array_index].subcategory_collection = [];
}
}
this.sub_value = true;
}
}
addQuestion(){
this._q_service.questionList().
subscribe(
data => {
this.add_question = Array.from(data);
this.question_value = [];
let id = 0;
let text = 'Select Question';
this.add_question.unshift({id,text});
this.subcategory_value = ['0'];
this.question_current = this.question_value;
},
err => console.error(err)
);
}
changedQuestion(data: any) {
this.question_current = data.value;
if(this.question_current != 0){
let len = this.add_question.length;
for (let i = 0; i < len; ++i) {
if (this.add_question[i].id == this.question_current) {
this.get_question = this.add_question[i].text;
}
}
}
}
addFormRow(){
let new_form ={
id: '',
segment: '',
category: '',
subcategory: '',
question: ''
};
// this.category_current.push(0);
let segment_categories = {
segment: '',
category: '',
subcategory: '',
question: ''
};
//this.category_current[form_array_index].category
this.collection_category.push(segment_categories);
this.forms.push(new_form);
}
*And every time the user hit the Add Form button it dynamically add form *
But it gives me an error every time I add form the first accordion is not working on the second form but the first form is working well

Categories