Variáveis ​​persistentes entre carregamentos de página

95

Estou tentando capturar o pressionamento do botão enviar do meu formulário e, se o formulário for enviado, a página é atualizada e eu mostro alguns campos ocultos. Eu gostaria de capturar se o formulário foi enviado antes ou não e se ele foi enviado no recarregamento, eu gostaria de reexibir os campos ocultos. Eu estava tentando usar uma variável global para fazer isso, mas não consegui fazê-la funcionar corretamente.

Aqui está o que eu tentei:

  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
    }
  });

Alguma sugestão sobre o que há de errado com este código?

Neófilo
fonte
1
Não acho que isso possa ser feito sem algum tipo de armazenamento. Suas variáveis ​​JS serão todas limpas. Todo o seu escopo será reciclado.
Dave Alperovich
Por que você não coloca a maior parte de sua página em uma "parcial" e atualiza isso?
Dave Alperovich
O que é parcial? Desculpe, não estou ciente disso.
Neófilo
Você considerou enviar o formulário via ajax e mostrar os campos após o envio?
dannyshaw
1
Você pode explicar por que precisa que a página seja atualizada? Se pudermos evitá-lo, você poderá fazer o que quiser se estiver apenas preventDefaultno submitevento (em vez do clickque está usando).
Peleg

Respostas:

202

Como o HTTP não tem estado, toda vez que você carregar a página, ele usará os valores iniciais de tudo o que você configurou em JavaScript. Você não pode definir uma variável global em JS e simplesmente manter esse valor após carregar a página novamente.

Existem algumas maneiras de armazenar o valor em outro lugar para que você possa inicializá-lo no carregamento usando JavaScript


String de consulta

Ao enviar um formulário usando o GETmétodo, o url é atualizado com uma string de consulta ( ?parameter=value&something=42). Você pode utilizar isso definindo um campo de entrada no formulário com um determinado valor. Este seria o exemplo mais simples:

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

No carregamento inicial da página, nenhuma string de consulta é definida. Ao enviar este formulário, a combinação namee valueda entrada são passadas na string de consulta como clicked=true. Portanto, quando a página for carregada novamente com essa string de consulta, você poderá verificar se o botão foi clicado.

Para ler esses dados, você pode usar o seguinte script no carregamento da 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');

( Fonte )

A capacidade de usar isso depende de como seu formulário funciona atualmente. Se você já usa um POST, isso pode ser problemático.

Além disso, para conjuntos de dados maiores, isso é menos do que ideal. Passar uma string não é grande coisa, mas para arrays e objetos de dados, você provavelmente deve usar o Web Storage ou cookies. Embora os detalhes difiram um pouco entre os navegadores, o limite prático para o comprimento do URI é de cerca de 2.000 caracteres


Armazenamento web

Com a introdução do HTML5, também obtivemos o Web Storage, que permite salvar informações no navegador durante o carregamento da página. Existe o localStorageque pode salvar dados por um período mais longo (desde que o usuário não os apague manualmente) e sessionStorageque salva os dados apenas durante a sua sessão de navegação atual. O último é útil para você aqui, porque você não deseja manter "clicado" definido como verdadeiro quando o usuário voltar mais tarde.

Aqui eu defino o armazenamento no evento de clique do botão, mas você também pode vinculá-lo ao envio de formulário ou qualquer outra coisa.

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

Então, ao carregar a página, você pode verificar se ela está definida usando o seguinte:

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

Mesmo que esse valor seja salvo apenas durante esta sessão de navegação, pode ser possível que você queira redefini-lo antes. Para fazer isso, use:

sessionStorage.removeItem('clicked');

Se você deseja salvar um objeto JS ou array, deve convertê-lo em uma string. De acordo com as especificações, deve ser possível salvar outros tipos de dados, mas isso ainda não foi implementado corretamente nos navegadores.

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

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

O suporte do navegador é muito bom, então você deve estar seguro para usá-lo, a menos que precise suportar navegadores realmente antigos / obscuros. O armazenamento na Web é o futuro.


Biscoitos

Uma alternativa ao Web Storage é salvar os dados em um cookie. Os cookies são feitos principalmente para ler dados do lado do servidor, mas também podem ser usados ​​para dados puramente do lado do cliente.

Você já usa jQuery, o que torna a configuração de cookies bastante fácil. Novamente, eu uso o clickevento aqui, mas poderia ser usado em qualquer lugar.

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

Então, no carregamento da página, você pode ler o cookie assim:

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

Como os cookies persistem em todas as sessões no seu caso, você precisará removê-los assim que fizer o que for necessário com eles. Você não gostaria que o usuário voltasse um dia depois e ainda tivesse clickeddefinido como verdadeiro.

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

(uma maneira não jQuery de definir / ler cookies pode ser encontrada aqui )

Eu pessoalmente não usaria um cookie para algo simples como lembrar um estado clicado, mas se a string de consulta não for uma opção e você precisar oferecer suporte a navegadores realmente antigos que não oferecem suporte a sessionStorage, isso funcionará. Você deve implementar isso com uma verificação de sessionStorage primeiro, e somente se isso falhar, use o método de cookie.


window.name

Embora isso pareça um hack para mim que provavelmente se originou antes de localStorage / sessionStorage, você pode armazenar informações na window.namepropriedade:

window.name = "my value"

Ele só pode armazenar strings, portanto, se você quiser salvar um objeto, terá de transformá-lo em string como no localStorageexemplo acima :

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

A principal diferença é que essas informações são retidas não apenas nas atualizações de página, mas também em diferentes domínios. No entanto, é restrito à guia atual em que você está.

Isso significa que você pode salvar algumas informações em sua página e, enquanto o usuário permanecer nessa guia, poderá acessar essas mesmas informações mesmo que ele navegue para outro site e volte. Em geral, eu desaconselho o uso disso, a menos que você realmente precise armazenar informações entre domínios durante uma única sessão de navegação.

Stephan Muller
fonte
9
Ugh, só depois de escrever eu li sua descrição de recompensa que dizia "sem cookies ou armazenamento local". Vou manter este comentário intacto para outros que possam precisar, mas você só precisará usar a string de consulta, eu acho.
Stephan Muller
1
Basicamente, já estou usando localStorage em muitos casos para meu aplicativo da web e gostaria de evitar o uso de muitas variáveis ​​localStorage. No entanto, gosto da ideia de remover o item localStorage assim que terminar de usá-lo. Isso foi algo em que não pensei ao usar minha variável localStorage.
Neófilo
3
Em caso de solicitação de postagem, você pode modificar a ação -attribute $ ("# formid"). Attr ("action", url + "& clicked = 1") e também detectar GET ou POST de $ ("# formid"). Attr ( "método"), mas pode não resolver como detectar o problema de recarregamento
Tero Tolonen
2
@TheNewbie já faz um tempo desde que escrevi esta resposta, mas acabei de adicionar uma nova opção ( window.name). Ele pode fazer exatamente o que você precisa, sem usar cookies / localStorage.
Stephan Muller
1
Eu queria acrescentar que o armazenamento local e de sessão também não são totalmente confiáveis ​​em navegadores mais recentes. Normalmente, há um fallback para window.name.
JavaScript de
5

Tente 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>

guest271314
fonte
1

Usar localeStorageou sessionStorageparece ser a melhor aposta.

Em vez de salvar a clickedvariável no escopo global, armazene-a desta maneira:

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
fonte
Pretendo não usar localstorage ou sessionStorage de preferência.
Neófilo
-5

Você pode tentar isto:

 $("input[type='submit'][value='Search']").click(function(){
     form.act.value='detailSearch'; 
     clicked = true;  
     return true;
});
Renakre
fonte
Quando a página é recarregada, o ainda recebe o valor clicado como falso.
Neófilo
1
@TheNewbie você acha que pode passar uma string de consulta? com a atualização da página, a abordagem atual não funcionará.
renakre