Problem
Rendered HTML template literal action events won't work
Stack MEVN with handlebars
code
renderData.js
const template = function (data) {
return `<div class="vvn_siteContent sc_flex">
<span class="sc_flex">
<img src="https://images.wallpaperscraft.com/image/single/keyboard_backlight_light_159518_1280x720.jpg" alt="" class="sc_img">
<div class="sc_flex sc_column">
<label class="sc_label">${data.category} :: ${data.titles.main}</label>
<div class="sc_desc" style="word-wrap: break-word">
${data.desc.main}
</div>
<div class="vvn_editTypes">
<button class="sc_button sc_resetBTN">Delete</button>
<button class="sc_button sc_scheduleBTN" >Hide</button>
<button class="sc_button sc_sendBTN" dataset-data="${data._id}" onclick="myData()" >Edit!</button>
</div>
</div>
</span>
</div>`
}
export const renderData = function (key) {
const keyToLowerCase = key.toLowerCase();
const getKeyData = handleJSON(keyToLowerCase);
getContainer.innerHTML = " ";
const parser = new DOMParser();
for (let i = 0; i < getKeyData[0][0].pageContent.length; i++) {
const { ...data } = getKeyData[0][0].pageContent[i];
const html = template(data);
const parsedDoc = parser.parseFromString(html, "text/html");
getContainer.append(...parsedDoc.body.children);
}
}
oneCRUD.js //this is the file that is loaded via
<script type="module" src="../js/OneCRUD.js" type="text/javascript" data="{{data2}}"></script>
this script tag is at the bottom of the index.html
const allBtns = document.querySelectorAll('.vvn_editTypes').forEach(el => el.addEventListener('click', (e) => {
console.log(e.target)
console.log(e)
if(e.target.textContent === 'Delete') console.log('Deleting')
if(e.target.textContent === 'Hide') console.log('Hiding')
if(e.target.textContent === 'Edit!') console.log('Editing')
}))
function myData () {
console.log('this wont get called even if i gave the button onclick="myData()")
}
If I try to call a function in onclick I will get error function name undefined
My problem is pretty straight forward. I am trying to attach events to the buttons in renderData.js from file oneCRUD.js and its not working.
Appreciate the help
I found a solution
code
const allBtns = document.querySelectorAll('.vvn_siteContent').forEach(el => el.addEventListener('click', (e) => {
console.log(e.target)
console.log(e)
if(e.target.textContent === 'Delete') console.log('Deleting')
if(e.target.textContent === 'Hide') console.log('Hiding')
if(e.target.textContent === 'Edit!') console.log('Editing')
}))
notice how the element I'm selecting is inside the template literal
I need to select the parent of that element.
so now my code looks like this:
const allBtns = document.querySelectorAll('.vvn_siteContentList').forEach(el => el.addEventListener('click', (e) => {
console.log(e.target)
console.log(e)
if(e.target.textContent === 'Delete') console.log('Deleting')
if(e.target.textContent === 'Hide') console.log('Hiding')
if(e.target.textContent === 'Edit!') console.log('Editing')
}))
now the allBtns function works.
why does this work?
thats a good question
Related
I'm having trouble retrieving data from a data-tag attribute on a button that is created by createElement
chatbot.js
const selectServiciosMoviles = document.querySelector('#selectServiciosMoviles')
const addSelect = (select, id, datatag) => {
const selection = document.createElement('button')
selection.classList.add('chatbot__selection')
selection.id = id
selection.setAttribute("data-tag", datatag)
selection.innerHTML = select
messageArea.appendChild(selection)
scrollToBottom(messageArea)
}
selectServiciosMoviles.addEventListener('click', () => {
setTimeout(() => {
addSelect('Portabilidad', 'selectPortabilidad', '{"categoria":"chatbot", "nombre":"chatbot","ubicacion":"home_b2b", "accion":"seleccionar", "etiqueta":"subcategoria_portabilidad"}')
addSelect('Planes Moviles', 'selectMoviles', '{"categoria":"chatbot", "nombre":"chatbot","ubicacion":"home_b2b", "accion":"seleccionar", "etiqueta":"subcategoria_planes_moviles"}')
addSelect('Roaming', 'selectRoaming', '{"categoria":"chatbot", "nombre":"chatbot","ubicacion":"home_b2b", "accion":"seleccionar", "etiqueta":"subcategoria_roaming"}')
addSelect('Seguro Movil', 'selectSeguros', '{"categoria":"chatbot", "nombre":"chatbot","ubicacion":"home_b2b", "accion":"seleccionar", "etiqueta":"subcategoria_seguro_movil"}')
scrollToBottom()
}, 2000)
});
html
<button class="chatbot__selection" id="selectPortabilidad" data-tag="{"categoria":"chatbot", "nombre","chatbot", "ubicacion":"home_b2b", "accion":"seleccionar","etiqueta":"subcategoria_portabilidad"}">Portabilidad</button>
<button class="chatbot__selection" id="selectMoviles" data-tag="{"categoria":"chatbot", "nombre","chatbot", "ubicacion":"home_b2b", "accion":"seleccionar","etiqueta":"subcategoria_portabilidad"}">Planes Moviles</button>
<button class="chatbot__selection" id="selectRoaming" data-tag="{"categoria":"chatbot", "nombre","chatbot", "ubicacion":"home_b2b", "accion":"seleccionar","etiqueta":"subcategoria_portabilidad"}">Roaming</button>
<button class="chatbot__selection" id="selectSeguros" data-tag="{"categoria":"chatbot", "nombre","chatbot", "ubicacion":"home_b2b", "accion":"seleccionar","etiqueta":"subcategoria_portabilidad"}">Seguro Movil</button>
libreria.js
var tagItems = document.querySelectorAll('[data-tag]')
tagItems.forEach(function (e) {
e.addEventListener('click', function (e) {
if(e.target.dataset.tag != undefined){
var data = JSON.parse(e.target.dataset.tag)
console.log(data)
}
})
})
the problem when seeing the console nothing appears to me, the data-tag of the button does not rescue me. please i need help, thanks
I use the JavaScript code below to get and log the attribute value of a div.
I want to rewrite the JavaScript code using React. When I tried doing the same code in React. I get error: e.path.find is not a function
How The Function Works:
First,after clicking mealsEl, e.path.find is used to go through all the child elements of meals EL,
Then it returns the child elements containing the class Name: 'meal-info'
Then it checks if the child element containing class Name 'meal-info' also has an attribute of 'data-meal-id.
Then it logs the value of 'data-meal-id'
const mealsEL = document.getElementById('meals')
mealsEL.addEventListener('click', (e) => {
const mealInfo = e.path.find((item) => {
console.log(item)
if (item.classList) {
return item.classList.contains('meal-info');
} else {
return false;
}
});
console.log(mealInfo)
if (mealInfo) {
const mealID = mealInfo.getAttribute('data-mealid');
getMealByID(mealID);
}
});
<div class="container">
<div id="result-heading"></div>
<div id="meals" class="meals">
<div class="meal">
<img class="meal-img" src="https://source.unsplash.com/random" alt="" style="width:180px; height: 180px;border: solid #000 4px;"/>
<div class="meal-info" >
</div>
</div>
</div>
<div id="single-meal"></div>
</div>
<div id="result-heading"></div>
<div id="meals" class="meals">
<div class="meal">
<img class="meal-img" src="https://source.unsplash.com/random" alt="" style="width:180px; height: 180px;border: solid #000 4px;"/>
<div class="meal-info" >
</div>
</div>
const mealsEL = document.getElementById('meals')
mealsEL.addEventListener('click', (e) => {
const mealInfo = e.path.find((item) => {
if (item.classList) {
console.log(item.classList)
return item.classList.contains("meal-info");
} else {
return false;
}
});
// console.log(mealInfo)
if (mealInfo) {
const mealID = mealInfo.getAttribute('data-mealid');
// getMealByID(mealID);
console.log(mealID)
} else {
console.log('no')
}
});
<div id="meals" class="meals">
<div class="meal">
<img class="meal-img" src="" alt="">
<div class="meal-info" data-mealid="75757">
<h3>Click To Show Data Meal Id</h3>
</div>
</div>
<!-- When mealsEL is clicked, the function uses e.path.find to check if the mealsEl children element contain a className of 'meal-info' and stores the result in the variable `const meal-info`
// The second if statement checks if the child element containing className meal-info has an attribute of 'data-mealid'
// Then the value of data-mealid attribute from the child element is logged to the console
</div> -->
// React Code
const getMealByID = (e) => {
const NativePath = e.nativeEvent()
const mealInfo = NativePath.path.find((item) => {
console.log(mealInfo)
if (item.classList) {
return item.classList.contains('meal-info');
} else {
return false;
}
});
if (mealInfo) {
const mealID = mealInfo.getAttribute('data-mealid');
getMealByID(mealID);
}
}
<div id="meals" className="meals" onClick={getMealByID}>
{meals &&
meals.map((meal) => {
const src = meal.strMealThumb;
const mealID = meal.idMeal;
const alt = meal.strMeal;
const index = meal.idMeal;
// const mealIng = meal.strIngredient1;
const mealIng = [];
for (let i = 1; i <= 20; i++) {
if (meal[`strIngredient${i}`]) {
mealIng.push(
`${meal[`strIngredient${i}`]} - ${meal[`strMeasure${i}`]}`
);
} else {
break;
}
}
return (
<div className="meal" key={index}>
<img className="meal-img" src={src} alt="{alt}" />
<div className="meal-info" data-mealid={mealID}>
<h3>{alt}</h3>
</div>
<h2>{mealIng}</h2>
</div>
);
})}
You are getting the error because you are calling getMealByID with an invalid argument, the function expect an event as argument:
if (mealInfo) {
const mealID = mealInfo.getAttribute('data-mealid');
getMealByID(mealID); //--> mealID is not an event
}
Also I think you can get the mealInfo node using less code:
const getMealByID = e => {
const node = e.target;
const mealInfo = node.querySelector(".meal-info");
if (mealInfo) {
const mealID = mealInfo.getAttribute("data-mealid");
...
}
};
// In order to get the data-mealid attribute value from a div
// by using its parent's element . I had to use
// e.target.getAttribute("data-mealid") on a click event from the parents element.
function App() {
const getMealInfoAttribute = e => {
const mealIDData = e.target.getAttribute("data-mealid")
console.log(mealID)
};
return (
<div id="meals" className="meals" onClick={getMealInfoAttribute}>
<div className="meal" key={index}>
<img className="meal-img" src={src} alt="{alt}" />
<div className="meal-info" data-mealid={mealID}>
<h3>{alt}</h3>
</div>
</div>
);
</div>)
}
Extract page.html:
<div id="46" class="cont-text-profile">
<span class="data"># March 4, 2021, 5:17 p.m.</span>
<p class="text">Tutto ok!!!!!!!111111111222222233333334444444</p>
<div class="edit"><a id="edit-46" href="javascript:void(0)" class="edit_post">Edit</a></div>
<div id="like" class="like"><a id="ilike-46" href="javascript:void(0)" class="like_post ">Like it?</a> (<span id="nlike-46">1</span> like)</div>
<div class="spacing"></div>
</div>
Extract script.js
document.addEventListener('DOMContentLoaded', function() {
const edit=document.getElementsByClassName('edit_post');
if (edit != null){
for (const ele of edit)
{ele.addEventListener('click',edit_post)}
}
});
function edit_post(e){
const id=parseInt(e.target.id.split('-')[1]);
const parent=document.getElementById(id);
if (parent != null){
const p=parent.querySelector('p')
const form=document.createElement('TEXTAREA');
form.id='d_textarea_'+id;
form.maxLength=260;
form.cols=52;
form.rows=4;
form.required;
form.classList.add('d_textarea');
form.value=p.innerHTML;
parent.replaceChild(form,p);
const all_edit_a=document.getElementsByClassName('edit_post');
for (let a of all_edit_a){
if (a.id == e.target.id){
e.target.innerHTML='Save';
e.target.addEventListener('click', save_post);
continue;}
a.removeEventListener('click',edit_post)
a.addEventListener('click', alert)
}
}
}
function save_post(e){
const id=parseInt(e.target.id.split('-')[1]);
const textarea = document.getElementById('d_textarea_'+id);
const edited_post = textarea.value;
if (edited_post == ''){
alert('The post cannot be empty, please write something.');
return false
}
fetch('/modify/' + id, {
method : 'PUT',
headers: {'Content-Type': 'text/html'},
body : edited_post
})
.then(response =>{
if (response.status != 200)
{
alert('Error. Please refresh page e retry. Err : ' + response.status);
}else{
const all_edit_a=document.getElementsByClassName('edit_post');
for (let a of all_edit_a){
if (a.id == e.target.id){
a.removeEventListener('click', save_post);
a.addEventListener('click',edit_post);
a.innerHTML='Edit';
continue;}
a.removeEventListener('click', alert);
a.addEventListener('click',edit_post);
}
const parent=document.getElementById(id);
const p=document.createElement('p');
p.classList.add('text');
p.innerHTML=edited_post;
parent.replaceChild(p,textarea);
}
})
.catch(error => {console.log('Error while processing the request:' , error);
})
}
function alert(){
alert('Save changes before leave please.');
}
The script works but it trown this error:
scripts.js:46 Uncaught TypeError: Cannot read property 'innerHTML' of null
at HTMLAnchorElement.edit_post
when i click on "Save" (and hence the handler again edit_post)
It seems the the handler "edit_post" will fired after a.addEventListener('click',edit_post);
First: I'm pretty sure you can't do this:
function alert(){
alert('Save changes before leave please.');
}
Second: try using the defer attribute
<script src="script.js" defer></script>
instead of
document.addEventListener('DOMContentLoaded', <...>);
I'm learning the basics with Javascript and I'm trying to do a modal that replace an alert, I'm almost done but I have a problem with the querySelector on the button to close it. It returns undefined even if I check it with the if conditional.
function getTemplate(templateName) {
let template = document.querySelector(templateName);
return template.innerHTML;
}
function createFragment(htmlStr) {
let frag = document.createDocumentFragment();
let temp = document.createElement('div');
temp.innerHTML = htmlStr;
while (temp.firstChild) {
frag.appendChild(temp.firstChild);
}
return frag;
}
function putTemplate(template) {
document.body.appendChild(createFragment(template));
}
function openAlert(alertName, btnOpen) {
let openBtn = document.querySelector(btnOpen);
openBtn.addEventListener('click', function () {
putTemplate(getTemplate(alertName));
});
}
function closeAlert(alertName, btnClose) {
let closeBtn = document.querySelector(btnClose);
if (closeBtn) {
closeBtn.addEventListener('click', function () {
let alertWrapper = document.querySelector(alertName);
alertWrapper.parentNode.removeChild(alertWrapper);
});
}
}
function Alert(alertName, btnOpen, btnClose) {
openAlert(alertName, btnOpen);
closeAlert(alertName, btnClose);
}
Alert('#alertTemplate', '.activeBtn', '.deactive');
And this is the markup:
<template id="alertTemplate">
<div id="alertWrapper">
<h1></h1>
<div class="alertBox confirmAlert" role="alert">
<p></p>
<button class="closeBtn deactive troll"></button>
<button class="acceptBtn deactive"></button>
</div>
</div>
</template>
``
I made buttons to switch language of data on click based on localStorage language item value, but it does not work as expected
HTML:
<a id="arbutton" href="#ar">arabic</a>
<a id="enbutton" href="#en">english</a>
<a id="" href="localStorage1.html">page</a>
<!-- data here will change -->
<div id="hello">yes language</div>
JS:
var creatbtnAr = document.querySelector('#arbutton');
var creatbtnEn = document.querySelector('#enbutton');
// button language arabic
creatbtnAr.addEventListener('click', event => {
localStorage.setItem("language", "ar");
console.log(localStorage.language);
});
// button language english
creatbtnEn.addEventListener('click', event => {
localStorage.setItem("language", "en");
console.log(localStorage.language);
});
// methods
var lg = localStorage.getItem.language;
function translate(lg) {
if(lg == 'ar') {
document.querySelector('#hello').textContent = 'u arabic';
}
if(lg == 'en') {
document.querySelector('#hello').textContent = 'u english';
}
}
https://codepen.io/pen/?editors=1111
Try this:
var creatbtnAr = document.querySelector('#arbutton');
var creatbtnEn = document.querySelector('#enbutton');
// button language arabic
creatbtnAr.addEventListener('click', event => {
localStorage.setItem("language", "ar");
console.log(localStorage.language);
translate();
});
// button language english
creatbtnEn.addEventListener('click', event => {
localStorage.setItem("language", "en");
console.log(localStorage.language);
translate();
});
// methods
function translate() {
const lg = localStorage.getItem("language");
if(lg == 'ar') {
document.querySelector('#hello').textContent = 'u arabic';
}
if(lg == 'en') {
document.querySelector('#hello').textContent = 'u english';
}
}