My Buttons are not working after using fetch api along with express.js - javascript

I have strange problem with buttons that are requesting for displaying templates on client page.
This is client side code. The main task of entire class is to just enable user to click button, send request and get response with HTML that has been rendered from handlebars template and just paste it in partiuclar place on client side. It works, but only once. After first click and displaying elements, I totally lose any interaction with those buttons. There is no request, and there is no even EventListener for clicking. I get no error. Completely there is no single reaction after clicking.
class Weapons {
constructor() {
this.buttons = document.querySelectorAll('.type')
}
async displayWeapon(path) {
const container = document.querySelector('.shop-container')
await fetch(`weapons/${path}`).then(response => response.json()).then(data => container.innerHTML += data);
}
chooseWeapon() {
this.buttons.forEach(btn => {
btn.addEventListener('click', (e) => {
console.log('click');
let weaponType = e.target.dataset.type
switch (weaponType) {
case 'pistols':
console.log('click');
return this.displayWeapon(weaponType)
case 'rifles':
console.log('click');
return this.displayWeapon(weaponType)
case 'grenades':
console.log('click');
return this.displayWeapon(weaponType)
case 'closerange':
console.log('click');
return this.displayWeapon(weaponType)
case 'rocketlauchner':
console.log('click');
return this.displayWeapon(weaponType)
}
})
})
}
}
document.addEventListener('DOMContentLoaded', function () {
const weapons = new Weapons();
weapons.chooseWeapon();
> When I invoke displayWeapon(path) here it also works, but immidiately
> after displaying html elements clicking on buttons again does not
> initiate any action.
})
Here is app.get function but I doubt it's source of problem.
app.get('/weapons/:id', (req, res) => {
console.log('req');
console.log(req.url);
let type = req.params.id;
res.render(type, function (err, html) {
res.json(html);
})
})

Ok. The answer is actually simple. In fetch function container.innerHTML += data. This line deletes my html with buttons, and the same time it deletes eventListeners. So I need just to modify my html.

Related

Javascript - Fetch request happening after it supposed

I'm still new to javascript, I have this javascript problem from CS50 that is supposed to open a mailbox and clicking on an email is supposed to open the email. I think my on click part of the problem is right, but when I open my page and click on an email it doesnt call the open_mail() function.
I've solved that the problem is that the load_mailbox function for being asynchronous is beign called after the DOM finishes to load, so technically theres no div with the class email-box when the DOM finishes to load, but i don't know how to solve this problem, can someone help please.
document.addEventListener('DOMContentLoaded', function() {
// Use buttons to toggle between views
document.querySelector('#inbox').addEventListener('click', () => load_mailbox('inbox'));
document.querySelector('#sent').addEventListener('click', () => load_mailbox('sent'));
document.querySelector('#archived').addEventListener('click', () => load_mailbox('archive'));
document.querySelector('#compose').addEventListener('click', compose_email);
document.querySelector('#compose-form').addEventListener('submit', send_mail);
document.querySelectorAll('.email-box').forEach(function(box) {
box.addEventListener('click', function (){
open_mail();
})
});
// By default, load the inbox
load_mailbox('inbox');
});
function load_mailbox(mailbox) {
fetch(`/emails/${mailbox}`)
.then(response => response.json())
.then(emails => {
document.querySelector('#email-content').innerHTML = "";
emails.forEach(inbox_mail);
})
};
function inbox_mail(email) {
const element = document.createElement('div');
if (document.querySelector(`#email-${email.id}`) === null) {
element.id = (`email-${email.id}`);
element.className = ("email-box");
element.innerHTML = `<p>From ${email.sender}</p><p>${email.subject}</p><p>At ${email.timestamp}
</p>`;
document.querySelector('#email-content').append(element);
}
}
I´d say the easiest solution would be to put the addEventListener to a point after the elements with class .email-box are created, e.g in your .then function after inbox_mail ran for each email
.then(emails => {
document.querySelector('#email-content').innerHTML = "";
emails.forEach(inbox_mail);
document.querySelectorAll('.email-box').forEach(function(box) {
box.addEventListener('click', function (){
open_mail();
});
});
});
DOMContentLoaded will trigger when the DOM from the initial request/response was loaded. What you are doing in your fetch callback is called "DOM-Manipulation" as you create elements and append them to the DOM that has already been loaded.

Does anyone know why this code is not working the way I want it to?

I am creating a web app with node.js, express and pug templates and here I am trying to simulate a warning when the user tries to remove a review he has posted.
so, in the front end I have a button that the user clicks to remove his review
when the user clicks that button I run
index.js
import { showWarning } from './warning';
const removerStoreReviewBtn = document.querySelector('.side-nav__removeStoreReviewbtn');
if (removerStoreReviewBtn)
removerStoreReviewBtn.addEventListener('click', e => {
e.preventDefault();
showWarning('Would you like to remove this review ?');
});
warning.js
export const hideWarning = () => {
const el = document.querySelector('.warning');
const warningText = document.querySelector('.warning__text');
if (el) el.parentElement.removeChild(el);
if (warningText) warningText.parentElement.removeChild(warningText);
};
export const showWarning = (msg, time = 30) => {
hideWarning();
console.log(msg);
const markUp = `
<div class="warning">
<div class="warning__text">${msg}</div>
<button class="warning--no">
<span>Cancelar</span>
</button>
<button class="warning--yes">
<span>Apagar</span>
</button>
</div>`;
document.querySelector('.header').insertAdjacentHTML('afterend', markUp);
window.setTimeout(hideWarning, time * 1000);
};
The showWarning function display everything the way I want in the front end
then back at the index.js file I have the following code
index.js
const warningBtnYes = document.querySelector('.warning--yes');
const warningBtnNo = document.querySelector('.warning--no');
if (warningBtnYes)
warningBtnYes.addEventListener('click', e => {
e.preventDefault();
console.log('remove');
//removerStoreReview(reviewId);
});
if (warningBtnNo)
warningBtnNo.addEventListener('click', e => {
e.preventDefault();
console.log('Do not remove');
});
when I click any of these buttons nothing happens (I am expecting the console.logs) and I can't figure out why nothing happens, hopefully anyone can help me.
Thanks
Mateus
When you use .parentElement.removeChild() you have turned off all event listeners for those button.
You have two options. You can preserve the event listeners by storing the return value from the .removeChild() call. In order to restore the event listeners you will need to reuse the stored (previously removed) node.
Alternatively, you'll need to re-add your event listeners after inserting the new HTML.
Helpful docs

html file button not clicking

i have this code that checks if the user has logged in or not, if the user has not logged in, it redirects the user to the login page to log in and if he/she has logged in, they would be allowed to upload content on the page. this is the code:
let vocals = document.getElementsByClassName("up");// class name of certain divs in the program
for (let i = 0; i < vocals.length; i++) {
vocals[i].addEventListener("click", () => {
let check = "php/checkCookie.php";
fetch(check, { method: "GET" })
.then((res) => res.text())
.then((data) => {
if (data == 0) {
shout("Login Before You Can Create", 0);
setInterval(() => {
location.href = "logincheck.html";
}, 3000);
} else {
document.getElementById(`e${i}`).click();
}
});
...
});
}
the code:
document.getElementById(`e${i}`).click();
is supposed to open the file explorer so that the user can pick a file and upload, but it doesn't work, and it does not show an error.
those anyone know why and has a solution, thanks in advance
Maybe your element doesn't support click() on it? If I remember correctly, click() works on on several elements, but not all. It should work on <input>, and <a>.
You could also try this instead:
document.getElementById(`e${i}`).dispatchEvent(new MouseEvent('mousedown'))
document.getElementById(`e${i}`).dispatchEvent(new MouseEvent('mouseup'))

javascript autoclick does not seem to autoclick

I'm really new to javascript and jquery and I'm trying to get a button to autoclick from an existing code base. I am having trouble getting the button to do that even though this is what I've been following How to auto click an input button.
The code is below. I've tried using both .submit() and .click() but the start-game-btn doesn't seem to get pressed either way. I've put a console.log within the button whenever it's pressed and the message doesn't seem to get logged.
console.log("loading...")
$(() => {
$("#start-game-btn").click(event => {
console.log("start-game")
$("#errors").text("")
event.preventDefault()
const height = parseInt($("#height").val())
const width = parseInt($("#width").val())
const food = parseInt($("#food").val())
let MaxTurnsToNextFoodSpawn = 0
if ($("#food-spawn-chance").val()) {
MaxTurnsToNextFoodSpawn = parseInt($("#food-spawn-chance").val())
}
const snakes = []
$(".snake-group").each(function() {
const url = "http://0.0.0.0:8080/"//$(".snake-url", $(this)).val()
console.log(url)
if (!url) {
return
}
snakes.push({
name: "M1",//$(".snake-name", $(this)).val(),
url
})
})
if (snakes.length === 0) {
$("#errors").text("No snakes available")
}
console.log(12)
fetch("http://localhost:3005/games", {
method: "POST",
body: JSON.stringify({
width,
height,
food,
MaxTurnsToNextFoodSpawn,
"snakes": snakes,
})
}).then(resp => resp.json())
.then(json => {
const id = json.ID
fetch(`http://localhost:3005/games/${id}/start`, {
method: "POST"
}).then(_ => {
$("#board").attr("src", `http://localhost:3009?engine=http://localhost:3005&game=${id}`)
}).catch(err => $("#errors").text(err))
})
.catch(err => $("#errors").text(err))
})
console.log("ready!")
})
window.onload = function(){
var button = document.getElementById('start-game-btn');
button.form.submit();
console.log("Done!!")
}
Everytime I refresh the page the log shows:
loading...
ready!
Done!!
What I think it should be logging is (or at least that's what I'm trying to achieve):
loading...
start-game
ready!
Done!!
submit() does not work because it is for submitting forms.
button.form.submit(); does not work because it assumes your button is part of a form.
As it looks like you are using jQuery, try just calling the jQuery click function without any parameters using a jQuery selector.
eg.
$("#start-game-btn").click();

Promise inside a forEach and variable references

I'm trying to make a simple Calendar app using Ionic (Cordova). I want to have a list of calendar events and a button next to each one which allows the user to add the event to his/her calendar or to remove it if it is already there. Also, I have put a button to add all the events to the calendar, for ease of use.
My problem is with using a Promise inside a forEach. Let me start with the code, which is from a Cordova (Ionic) app:
addAllEvents() {
this.events.forEach((event: CalendarEvent, index, array) => {
Calendar.createEvent(event.title, event.location, event.notes, event.startDate, event.endDate).then(
(msg) => {
console.log(msg);
event.isInCalendar = true;
},
(err) => {
console.log(err);
}
);
});
}
What addAllEvents() should do is (upon a button being pressed on the page) add all of the CalendarEvents in the events array to the user's Calendar and update the event's isInCalendar property to true. isInCalendar is used to decide which button to show next to each event (Add or Remove):
<button *ngIf="!event.isInCalendar;" ion-button rounded (click)="addEventToCalendar(i);">Add to calendar</button>
<button *ngIf="event.isInCalendar;" ion-button color="danger" rounded (click)="removeEventFromCalendar(i);">Remove from calendar</button>
However, upon execution, addAllEvents() only changes the isInCalendar property of the last event! (judging by the fact that only the last button changes)
What I suspect is happening is that forEach binds event to each consecutive item in the events array and by the time the Promises returned by Calendar resolve, the event object references the last item in the events array, which means that the Promises are modifying only the last event.
Please help me resolve this confusion!
P.S.
The individual addEventToCalendar() and removeEventFromCalendar() functions are working correctly. Here is their code:
addEventToCalendar(index: number) {
let event = this.events[index];
Calendar.createEvent(event.title, event.location, event.notes, event.startDate, event.endDate).then(
(msg) => {
console.log(msg);
event.isInCalendar = true;
},
(err) => {
console.log(err);
}
);
}
removeEventFromCalendar(index: number) {
let event = this.events[index];
Calendar.deleteEvent(event.title, event.location, event.notes, event.startDate, event.endDate).then(
(msg) => {
console.log(msg);
event.isInCalendar = false;
},
(err) => {
console.log(err);
}
);
}

Categories

Resources