The function below is inside another function called calculate()
. The calculate function is triggered every time I press a specific button.
The problem is for every time I am clicking that button the function below is generating multiple files and when I click to download, all the files generated are downloaded, which is not supposed to happen. It should only download the last generated file.
function CalculateMedia() {
// Defining every var to retrieve the values from inputs
let TrienalHolder = document.getElementById('trienal');
let trienal = (TrienalHolder.options[TrienalHolder.selectedIndex]).textContent;
let BienalIHolder = document.getElementById('bienal_i');
let bienal_i = (BienalIHolder.options[BienalIHolder.selectedIndex]).textContent;
let BienalIIHolder = document.getElementById('bienal_ii');
let bienal_ii = (BienalIIHolder.options[BienalIIHolder.selectedIndex]).textContent;
// Média de cada disciplina por ano, Provas de Ingresso, Peso PI e Peso Média
let pt10 = document.getElementById("pt_10").value;
let pt11 = document.getElementById("pt_11").value;
let pt12 = document.getElementById("pt_12").value;
let le10 = document.getElementById("le_10").value;
let le11 = document.getElementById("le_11").value;
let fil10 = document.getElementById("fil_10").value;
let fil11 = document.getElementById("fil_11").value;
let trienal10 = document.getElementById("trienal_10").value;
let trienal11 = document.getElementById("trienal_11").value;
let trienal12 = document.getElementById("trienal_12").value;
let bienali10 = document.getElementById("bienal_i_10").value;
let bienali11 = document.getElementById("bienal_i_11").value;
let bienalii10 = document.getElementById("bienal_ii_10").value;
let bienalii11 = document.getElementById("bienal_ii_11").value;
let edf10 = document.getElementById("edf_10").value;
let edf11 = document.getElementById("edf_11").value;
let edf12 = document.getElementById("edf_12").value;
let anuali = document.getElementById("anual_i").value;
let anualii = document.getElementById("anual_ii").value;
let Pi1 = document.getElementById("pi_pt").value;
let Pi2 = document.getElementById("pi_le").value;
let Pi3 = document.getElementById("pi_fil").value;
let Pi4 = document.getElementById("pi_trienal").value;
let Pi5 = document.getElementById("pi_bienal_i").value;
let Pi6 = document.getElementById("pi_bienal_ii").value;
let PPI = document.getElementById("peso_pi").value;
//Média Final de cada disciplina
let pt_final = (parseFloat(pt10) + parseFloat(pt11) + parseFloat(pt12)) / 3;
let le_final = (parseFloat(le10) + parseFloat(le11)) / 2;
let fil_final = (parseFloat(fil10) + parseFloat(fil11)) / 2;
let trienal_final = (parseFloat(trienal10) + parseFloat(trienal11) + parseFloat(trienal12)) / 3;
let bienal_i_final = (parseFloat(bienali10) + parseFloat(bienali11)) / 2;
let bienal_ii_final = (parseFloat(bienalii10) + parseFloat(bienalii11)) / 2;
let edf_final = (parseFloat(edf10) + parseFloat(edf11) + parseFloat(edf12)) / 3;
let anual_i_final = parseFloat(anuali);
let anual_ii_final = parseFloat(anualii);
let PiPt = (parseFloat(Pi1)) / 10;
let PiLe = (parseFloat(Pi2)) / 10;
let PiFil = (parseFloat(Pi3)) / 10;
let PiTrienal = (parseFloat(Pi4)) / 10;
let PiBienali = (parseFloat(Pi5)) / 10;
let PiBienalii = (parseFloat(Pi6)) / 10;
let PesoProvasIngresso = (parseFloat(PPI)) / 100;
let PesoMediaFinal = 1 - PesoProvasIngresso;
let MediaFinalSecundario = ((pt_final + le_final + fil_final + trienal_final + bienal_i_final + bienal_ii_final + edf_final + anual_i_final + anual_ii_final) / 9).toFixed(2);
//This part of the code puts the PI into an array and only returns the not NaN after that it calculates the average
let piArray = [PiPt, PiLe, PiFil, PiTrienal, PiBienali, PiBienalii];
let validPiArray = piArray.filter(function(value) {
return !isNaN(value);
});
let MediaProvasIngresso = validPiArray.length > 0 ? validPiArray.reduce(function(acc, value) {
return acc + value;
}, 0) / validPiArray.length : 0;
let MediaFinalAcessoES = ((MediaFinalSecundario * PesoMediaFinal) + (MediaProvasIngresso * PesoProvasIngresso)).toFixed(2);
let checkboxes = document.querySelectorAll("[id^='check_']");
let atLeastOneChecked = false;
for (let i = 0; i < checkboxes.length; i++) {
if (checkboxes[i].checked) {
atLeastOneChecked = true;
break;
}
}
if (atLeastOneChecked) {
document.getElementById("media-secundarioES").textContent = `${MediaFinalSecundario}`;
document.getElementById("media-ES").textContent = `${MediaFinalAcessoES}`;
$('#notafinalES').modal('show');
} else {
document.getElementById("media-secundario").textContent = `${MediaFinalSecundario}`;
$('#notafinal').modal('show');
}
let excelFileDownloaded = false;
// Export to excel function
async function generateAndDownloadExcel(fillB19 = true) {
if (excelFileDownloaded) {
return;
}
// Load the template.xlsx file using fetch API
const workbook = new ExcelJS.Workbook();
const response = await fetch('ExcelTemplate.xlsx');
const arrayBuffer = await response.arrayBuffer();
// Read the Excel file from the Blob
await workbook.xlsx.load(arrayBuffer);
// Get the first sheet of the workbook
const sheet = workbook.getWorksheet(1);
// Update cell values
sheet.getCell('B6').value = pt10;
sheet.getCell('C6').value = pt11;
sheet.getCell('D6').value = pt12;
sheet.getCell('B7').value = le10;
sheet.getCell('C7').value = le11;
sheet.getCell('B8').value = fil10;
sheet.getCell('C8').value = fil11;
sheet.getCell('B9').value = trienal10;
sheet.getCell('C9').value = trienal11;
sheet.getCell('D9').value = trienal12;
sheet.getCell('B10').value = bienali10;
sheet.getCell('C10').value = bienali11;
sheet.getCell('B11').value = bienalii10;
sheet.getCell('C11').value = bienalii11;
sheet.getCell('B12').value = edf10;
sheet.getCell('C12').value = edf11;
sheet.getCell('D12').value = edf12;
sheet.getCell('D13').value = anuali;
sheet.getCell('D14').value = anualii;
sheet.getCell('E6').value = Pi1;
sheet.getCell('E7').value = Pi2;
sheet.getCell('E8').value = Pi3;
sheet.getCell('E9').value = Pi4;
sheet.getCell('E10').value = Pi5;
sheet.getCell('E11').value = Pi6;
sheet.getCell('B16').value = PPI;
sheet.getCell('B18').value = MediaFinalSecundario;
if (fillB19) {
sheet.getCell('B19').value = MediaFinalAcessoES;
}
sheet.getCell('A9').value = trienal;
sheet.getCell('A10').value = bienal_i;
sheet.getCell('A11').value = bienal_ii;
// Generate the Excel file and download it
const buffer = await workbook.xlsx.writeBuffer();
const blob = new Blob([buffer], {
type: 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'
});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
let currentDate = new Date().toLocaleDateString().replaceAll('/', '-');
let fileName = `MediaCalculada[${currentDate}].xlsx`;
a.href = url;
a.download = fileName;
a.click();
setTimeout(() => URL.revokeObjectURL(url), 1000);
excelFileDownloaded = true;
}
const downloadButton = document.getElementById('downloadButton');
const downloadButtonES = document.getElementById('downloadButtonES');
downloadButton?.addEventListener('click', () => {
generateAndDownloadExcel(false);
});
downloadButtonES?.addEventListener('click', () => {
generateAndDownloadExcel();
});
}
2
Answers
Looks like you’re registering multiple
EventListeners
every time your calculate button is clicked.Let’s imagine a scenario:
calculate()
EventListener
forclick
event ondownloadButton
is registeredEventListener
forclick
event ondownloadButtonES
is registeredcalculate()
once againEventListener
forclick
event ondownloadButton
is registeredEventListener
forclick
event ondownloadButtonES
is registeredAt this point each of the button has two
EventListeners
for aclick
action – as a result two actions will be performed.As you’re assigning an arrow function, it will be a new arrow function every time you register
EventListener
. You can avoid it by creating named functions and assigning them as callbacks.In JavaScript you can only register one handler for the same event that has the same callback.
Implementing the following change should address the issue, however, your handlers might need to be in the outer scope to ensure they do not get redefined when
calculate()
is executed – but it is quite hard to tell without seeing the full code.I would think you need to stop the function here:
and then delegate