skip to Main Content

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


  1. Looks like you’re registering multiple EventListeners every time your calculate button is clicked.

    Let’s imagine a scenario:

    • You click the button which calls calculate()
    • EventListener for click event on downloadButton is registered
    • EventListener for click event on downloadButtonES is registered
    • You click the button which calls calculate() once again
    • EventListener for click event on downloadButton is registered
    • EventListener for click event on downloadButtonES is registered

    At this point each of the button has two EventListeners for a click 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.

    function clickHandler() {
        generateAndDownloadExcel(false);
    }
    
    function clickHandlerES() {
        generateAndDownloadExcel();
    }
    
    downloadButton?.addEventListener('click', clickHandler);
          
    downloadButtonES?.addEventListener('click', clickHandlerES);
    
    Login or Signup to reply.
  2. I would think you need to stop the function here:

      }
    } // end of CalculateMedia
    let excelFileDownloaded = false;
    

    and then delegate

      excelFileDownloaded = true;
    }
    document.querySelector(".someClassOfACommonStaticContainer')
      .addEventListener('click', (e) => {
      const tgt = e.target;
      if (tgt.matches("#downloadButton")) generateAndDownloadExcel(false);
      else if (tgt.matches("#downloadButtonES")) generateAndDownloadExcel();
    });
    
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search