Conservar variables entre cargas de página

97

Estoy tratando de capturar la pulsación del botón de envío de mi formulario y, si se envía el formulario, la página se actualiza y muestro algunos campos ocultos. Me gustaría capturar si el formulario se envió antes o no y si se envió al recargar, me gustaría mostrar los campos ocultos. Estaba tratando de usar una variable global para lograr esto, sin embargo, no pude hacer que funcionara correctamente.

Esto es lo que probé:

  var clicked = false;

  $(document).ready(function() {

    $("input[type='submit'][value='Search']").attr("onclick", "form.act.value='detailSearch'; clicked = true;  return true;");

    if (clicked == true) {
      // show hidden fields
    } else {
      // don't show hidden fields
    }
  });

¿Alguna sugerencia sobre lo que está mal con este código?

Neófilo
fuente
1
No creo que esto se pueda hacer sin algún tipo de almacenamiento. Todas sus variables JS quedarán limpias. Todo tu alcance será reciclado.
Dave Alperovich
¿Por qué no pones la mayor parte de tu página en un "parcial" y actualizas eso?
Dave Alperovich
¿Qué es un parcial? Lo siento, no soy consciente de eso.
Neophile
¿Ha considerado enviar el formulario a través de ajax y mostrar los campos después del envío?
dannyshaw
1
¿Puede explicar por qué necesita que la página se actualice? Si podemos evitarlo, es posible que pueda hacer lo que quiera si solo está preventDefaulten el submitevento (en lugar del clickque está usando).
Peleg

Respuestas:

207

Como HTTP no tiene estado, cada vez que cargue la página, usará los valores iniciales de lo que establezca en JavaScript. No puede establecer una variable global en JS y simplemente hacer que ese valor permanezca después de cargar la página nuevamente.

Hay un par de formas en que puede almacenar el valor en otro lugar para que pueda inicializarlo en la carga usando JavaScript


Cadena de consulta

Al enviar un formulario utilizando el GETmétodo, la URL se actualiza con una cadena de consulta ( ?parameter=value&something=42). Puede utilizar esto configurando un campo de entrada en el formulario con un valor determinado. Este sería el ejemplo más simple:

<form method="GET">
    <input type="hidden" name="clicked" value="true" />
    <input type="submit" />
</form>

En la carga inicial de la página, no se establece ninguna cadena de consulta. Cuando envía este formulario, la combinación namey valuede la entrada se pasa en la cadena de consulta como clicked=true. Entonces, cuando la página se cargue nuevamente con esa cadena de consulta, puede verificar si se hizo clic en el botón.

Para leer estos datos, puede utilizar el siguiente script al cargar la página:

function getParameterByName(name) {
    name = name.replace(/[\[]/, "\\[").replace(/[\]]/, "\\]");
    var regex = new RegExp("[\\?&]" + name + "=([^&#]*)"),
        results = regex.exec(location.search);
    return results === null ? "" : decodeURIComponent(results[1].replace(/\+/g, " "));
}

var clicked = getParameterByName('clicked');

( Fuente )

La capacidad de usar esto depende de cómo funcione su formulario actualmente, si ya usa un POST, esto podría ser problemático.

Además, para conjuntos de datos más grandes, esto no es óptimo. Pasar una cadena no es un gran problema, pero para las matrices y los objetos de datos probablemente debería usar almacenamiento web o cookies. Si bien los detalles difieren un poco entre los navegadores, el límite práctico para la longitud de URI es de alrededor de 2000 caracteres.


Almacenamiento web

Con la introducción de HTML5 también obtuvimos almacenamiento web, que le permite guardar información en el navegador a través de cargas de página. Existe la localStorageque puede guardar datos durante un período más largo (siempre que el usuario no los borre manualmente) y la sessionStorageque guarda datos solo durante su sesión de navegación actual. Este último es útil para usted aquí, porque no desea mantener "clic" establecido en verdadero cuando el usuario regrese más tarde.

Aquí configuro el almacenamiento en el evento de clic de botón, pero también puede vincularlo al envío de formulario o cualquier otra cosa.

$('input[type="submit"][value="Search"]').click(function() {
    sessionStorage.setItem('clicked', 'true');
});

Luego, cuando cargue la página, puede verificar si está configurada usando esto:

var clicked = sessionStorage.getItem('clicked');

Aunque este valor solo se guarda durante esta sesión de navegación, es posible que desee restablecerlo antes. Para hacerlo, use:

sessionStorage.removeItem('clicked');

Si desea guardar un objeto o matriz JS, debe convertirlo en una cadena. Según la especificación, debería ser posible guardar otros tipos de datos, pero esto aún no se ha implementado correctamente en los navegadores.

//set
localStorage.setItem('myObject', JSON.stringify(myObject));

//get
var myObject = JSON.parse(localStorage.getItem('myObject'));

El soporte del navegador es bastante bueno, por lo que debería estar seguro de usarlo a menos que necesite ser compatible con navegadores realmente antiguos / oscuros. Web Storage es el futuro.


Galletas

Una alternativa al almacenamiento web es guardar los datos en una cookie. Las cookies están diseñadas principalmente para leer datos del lado del servidor, pero también se pueden utilizar para datos puramente del lado del cliente.

Ya usas jQuery, lo que facilita la configuración de cookies. Nuevamente, utilizo el clickevento aquí, pero podría usarse en cualquier lugar.

$('input[type="submit"][value="Search"]').click(function() {
    $.cookie('clicked', 'true', {expires: 1}); // expires in 1 day
});

Luego, al cargar la página, puede leer la cookie de esta manera:

var clicked = $.cookie('clicked');

Como las cookies persisten a lo largo de las sesiones en su caso, deberá desactivarlas tan pronto como haya hecho lo que sea necesario para hacer con ellas. No querrá que el usuario regrese un día después y aún así se haya clickedconfigurado como verdadero.

if(clicked === "true") {
    //doYourStuff();
    $.cookie('clicked', null);
}

(una forma no jQuery para configurar / leer cookies se puede encontrar aquí )

Personalmente, no usaría una cookie para algo tan simple como recordar un estado en el que se hizo clic, pero si la cadena de consulta no es una opción y necesita ser compatible con navegadores realmente antiguos que no admiten sessionStorage, esto funcionará. Primero debe implementar eso con una verificación de sessionStorage, y solo si eso falla, use el método de cookies.


window.name

Aunque esto me parece un truco que probablemente se originó antes de localStorage / sessionStorage, podría almacenar información en la window.namepropiedad:

window.name = "my value"

Solo puede almacenar cadenas, por lo que si desea guardar un objeto, deberá clasificarlo como en el localStorageejemplo anterior :

window.name = JSON.stringify({ clicked: true });

La principal diferencia es que esta información se conserva no solo en las actualizaciones de página, sino también en diferentes dominios. Sin embargo, está restringido a la pestaña actual en la que se encuentra.

Esto significa que puede guardar cierta información en su página y, siempre que el usuario permanezca en esa pestaña, puede acceder a esa misma información incluso si navega a otro sitio web y regresa. En general, aconsejaría no usar esto a menos que realmente necesite almacenar información entre dominios durante una sola sesión de navegación.

Stephan Muller
fuente
9
Uf, solo después de escribir leí la descripción de su recompensa que decía "sin cookies ni almacenamiento local". Mantendré este comentario intacto para otros que puedan necesitarlo, pero supongo que solo necesitará usar la cadena de consulta.
Stephan Muller
1
Básicamente, ya estoy usando localStorage en muchos casos para mi aplicación web y me gustaría evitar usar demasiadas variables localStorage. Sin embargo, me gusta la idea de eliminar el elemento localStorage una vez que haya terminado. Eso fue algo en lo que no pensé cuando usé mi variable localStorage.
Neófilo
3
En caso de una solicitud de publicación, puede modificar la acción -attribute $ ("# formid"). Attr ("action", url + "& clicked = 1") y también detectar GET o POST desde $ ("# formid"). Attr ( "método"), pero puede que no resuelva cómo detectar el problema de recarga
Tero Tolonen
2
@TheNewbie ha pasado un tiempo desde que escribí esta respuesta, pero acabo de agregar una nueva opción ( window.name). Puede que haga exactamente lo que necesita sin usar cookies / localStorage.
Stephan Muller
1
Quería agregar que el almacenamiento local y de sesión tampoco es totalmente confiable en los navegadores más nuevos. Por lo general, hay una alternativa a window.name.
JavaScript
5

Intente utilizar $.holdReady(),history

function show() {
  return $("form input[type=hidden]")
          .replaceWith(function(i, el) {
            return "<input type=text>"
          });
}

$.holdReady(true);
    if (history.state !== null && history.state.clicked === true) {
       // show hidden fields
       // if `history.state.clicked === true` ,
       // replace `input type=hidden` with `input type=text`
       show();
       console.log(history);

    } else {
        // don't show hidden fields
        console.log(history);
    }
$.holdReady(false);

  $(document).ready(function() {

    $("input[type=submit][value=Search]")
    .on("click", function(e) {
        e.preventDefault();
        if (history.state === null) {
          // do stuff
          history.pushState({"clicked":true});
          // replace `input type=hidden` with `input type=text`
          show();
          console.log(history);
        } else {
          // do other stuff
        };
    });

  });
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<form method="POST">
    <input type="text" name="name" value="" />
    <input type="submit" value="Search" />
    <input type="hidden" />
    <input type="hidden" />
</form>

invitado271314
fuente
1

Usar localeStorageo sessionStorageparece ser la mejor opción.

En lugar de guardar la clickedvariable en el alcance globle, guárdelo de esta manera:

if(localeStorage.getItem("clicked") === null)
    localeStorage.setItem("clicked", "FALSE"); // for the first time

$(document).ready(function() {

    $("input[type='submit'][value='Search']").attr("onclick", "form.act.value='detailSearch';return true;");

    var clicked = localeStorage.getItem("clicked") == "FALSE" ? "TRUE" : "FALSE";

    localeStorage.setItem("clicked", clicked);

    if (clicked == "TRUE") {
      // show hidden fields
    } else {
      // don't show hidden fields
    }

});
me_digvijay
fuente
Tengo la intención de no usar localstorage o sessionStorage preferiblemente.
Neophile
-5

Puedes probar esto:

 $("input[type='submit'][value='Search']").click(function(){
     form.act.value='detailSearch'; 
     clicked = true;  
     return true;
});
renakre
fuente
Cuando la página se recarga, el valor en el que se hizo clic es falso.
Neófilo
1
@TheNewbie, ¿cree que puede pasar una cadena de consulta? con la actualización de la página, el enfoque actual no funcionará.
Renakre