2012-08-01 9 views
25

Sto utilizzando window.onbeforeunload per impedire all'utente di spostarsi dopo aver modificato i valori in un modulo. Funziona bene, tranne che mostra anche l'avviso quando l'utente invia il modulo (non desiderato).window.onbeforeunload - Mostra solo avviso quando non si invia il modulo

Come posso fare questo senza mostrare l'avviso quando il modulo viene inviato?

codice attuale:

var formHasChanged = false; 

$(document).on('change', 'form.confirm-navigation-form input, form.confirm-navigation-form select, form.confirm-navigation-form textarea', function (e) { 
    formHasChanged = true; 
}); 

$(document).ready(function() { 
    window.onbeforeunload = function (e) { 
     if (formHasChanged) { 
      var message = "You have not saved your changes.", e = e || window.event; 
      if (e) { 
       e.returnValue = message; 
      } 
      return message; 
     } 
    } 
}); 

risposta

26

Utilizzando presentare evento del form per impostare un flag potrebbe funzionare per voi .

var formHasChanged = false; 
var submitted = false; 

$(document).on('change', 'form.confirm-navigation-form input, form.confirm-navigation-form select, form.confirm-navigation-form textarea', function (e) { 
    formHasChanged = true; 
}); 

$(document).ready(function() { 
    window.onbeforeunload = function (e) { 
     if (formHasChanged && !submitted) { 
      var message = "You have not saved your changes.", e = e || window.event; 
      if (e) { 
       e.returnValue = message; 
      } 
      return message; 
     } 
    } 
$("form").submit(function() { 
    submitted = true; 
    }); 
}); 
+0

Ho accettato questo sopra @ Derek perché avevo già un codice di invio personalizzato e dovevo controllare separatamente i due valori. – mtmurdock

10

È possibile gestire l'evento submit(), che avverrà solo per vostro modulo di presentazione.

All'interno di questo evento, impostare la variabile flag formHasChanged su false per consentire allo scaricamento di procedere. Inoltre, solo un suggerimento, ma dal momento che lo scopo di tale variabile bandiera sarà cambiato, quindi si consiglia di rinominarlo qualcosa come 'warnBeforeUnload'

$(document).submit(function(){ 
    warnBeforeUnload = false; 
}); 
11

si potrebbe usare .on() per associare onbeforeunload e quindi utilizzare .OFF() per sciogliere in forma di presentazione

$(document).ready(function() { 
    // Warning 
    $(window).on('beforeunload', function(){ 
     return "Any changes will be lost"; 
    }); 

    // Form Submit 
    $(document).on("submit", "form", function(event){ 
     // disable warning 
     $(window).off('beforeunload'); 
    }); 
} 
2

ero alla ricerca di una soluzione migliore per questo. Quello che vogliamo è semplicemente escludere uno o più trigger dal creare il nostro "Sei sicuro?" la finestra di dialogo. Quindi non dovremmo creare più soluzioni alternative per sempre più effetti collaterali. Cosa succede se il modulo viene inviato senza un evento click del pulsante di invio? Cosa succede se il nostro gestore di clic rimuove lo stato isDirty ma successivamente il modulo di invio viene bloccato in seguito? Certo, possiamo cambiare il comportamento dei nostri trigger, ma il posto giusto sarebbe la logica che gestisce il dialogo. Il binding all'evento submit del modulo anziché il binding all'evento click del pulsante di invio è un vantaggio delle risposte in questo thread rispetto ad altre che ho visto prima, ma questo IMHO risolve solo l'approccio sbagliato.

Dopo alcuni scavi nell'evento evento dell'evento onbeforeunload ho trovato la proprietà .target.activeElement, che contiene l'elemento, che ha originariamente originato l'evento. Quindi, sì, è il pulsante o il collegamento o qualsiasi cosa abbiamo cliccato (o nulla del tutto, se il browser stesso ha navigato lontano). Il nostro "Sei sicuro?" dialogo logica poi si riduce a due componenti seguenti:

  1. La isDirty manipolazione della forma: "Sei sicuro"

    $('form.pleaseSave').on('change', function() { 
        $(this).addClass('isDirty'); 
    }); 
    
  2. Il dialogo logica:

    $(window).on('beforeunload', function(event) { 
        // if form is dirty and trigger doesn't have a ignorePleaseSave class 
        if ($('form.pleaseSave').hasClass('isDirty') 
         && !$(event.target.activeElement).hasClass('ignorePleaseSave')) { 
        return "Are you sure?" 
        } 
        // special hint: returning nothing doesn't summon a dialog box 
    }); 
    

E 'semplicemente come questo. Non sono necessari soluzioni alternative. Basta dare i trigger (invio e altri pulsanti di azione) una classe ignorePleaseSave e il modulo a cui vogliamo che la finestra di dialogo venga applicata a una classe pleaseSave. Tutti gli altri motivi per scaricare la pagina poi convoca il nostro "Sei sicuro?" dialogo.

P.S. Sto usando jQuery qui, ma penso che la proprietà .target.activeElement sia disponibile anche in semplice JavaScript.

+0

Questo sembra essere specifico per il browser. Funziona bene in Chrome ma l'obiettivo in Firefox è sempre 'body' –

+0

Appena testato in Firefox 40, event.target.activeElement fornisce in effetti l'elemento con clock, come fa in Chrome. La mia soluzione funziona bene con entrambi i browser. – spackmat

+0

Mi piace questo approccio ma non riuscivo a farlo funzionare in IE. Ma ignorando completamente l'evento e usando document.activeElement ho fatto il trucco per me (testato solo su Chrome e IE fino ad ora) – Doogal

Problemi correlati