javascriptc#razor

I need to fire an event for the IndexModel when the user closes the page


This is my code:

<script>
    function sendFieldData() {
        var email = document.getElementById('EmailComprador').value;
        var telefone = document.getElementById('TelefoneComprador2').value;
        var nome = document.getElementById('NomeComprador2').value;

        var data = {
            CustomerEmail: email,
            CustomerName: nome,
            CustomerPhone: telefone,
        };

        if (email) {
            let curfetchUrl = `${window.location.pathname}?handler=SaveAbandonedCart`;
            fetch(curfetchUrl, {
                method: 'POST',
                headers: {
                    'Content-Type': 'application/json',
                    'RequestVerificationToken': document.querySelector('input[name="__RequestVerificationToken"]').value
                },
                body: JSON.stringify(data)
            })
                .then(response => {
                    if (!response.ok) {
                        return response.text().then(text => { throw new Error(text); });
                    }
                    return response.json();
                })
                .then(responseData => {
                    console.log('salvo com sucesso', responseData);
                })
                .catch(error => {
                    console.error('erro:', error);
                });
        }
    }
    window.addEventListener('beforeunload', function (event) {
        setTimeout(sendFieldData, 0);
    });
</script>

At first it only calls the method on the IndexModel when I reload the page, but that's not what I want. I want when the user clicks on close tab to trigger the event to the backend as well.

Obs.: I already used unload, it didn't work. I'm using Razor, Js and C#


Solution

  • The issue is that the beforeunload event listener is not reliable. Sending analytics when the page closes has become so commonplace that an API was added to handle it: Beacon API

    Here's your JavaScript with that adjustment. Note that I moved some logic around a bit so we can build the data object before sending the beacon.

    function getData() {
      var email = document.getElementById("EmailComprador").value;
      var telefone = document.getElementById("TelefoneComprador2").value;
      var nome = document.getElementById("NomeComprador2").value;
      return {
        CustomerEmail: email,
        CustomerName: nome,
        CustomerPhone: telefone,
      };
    }
    
    document.addEventListener("visibilitychange", function logData() {
      if (document.visibilityState === "hidden") {
        const curfetchUrl = `${window.location.pathname}?handler=SaveAbandonedCart`;
        const data = getData();
        if (data.CustomerEmail) {
          const requestSucceeded = navigator.sendBeacon(
            curfetchUrl,
            JSON.stringify(data)
          );
          if (requestSucceeded) {
            console.log("salvo com sucesso");
          } else {
            console.error("erro");
          }
        }
      }
    });
    

    If there are issues with using this API, like if you need to customize request properties or need to handle the response from the server, then this won't be a good fit. Instead try your original code but add "keepalive: true" to the fetch call. You'll also need to switch to using visibilitychange instead of beforeunload like in the first example.

    //...
        fetch(curfetchUrl, {
          method: "POST",
          keepalive: true, // here's the adjustment
          headers: {
            "Content-Type": "application/json",
            RequestVerificationToken: document.querySelector(
              'input[name="__RequestVerificationToken"]'
            ).value,
          },
          body: JSON.stringify(data),
        })
    //...