Utrwalaj zmienne między wczytywaniem stron

97

Próbuję uchwycić przycisk Wyślij mój formularz, a jeśli formularz zostanie przesłany, strona odświeża się i pokazuję kilka ukrytych pól. Chciałbym uchwycić, czy formularz został przesłany wcześniej, czy nie, a jeśli został przesłany ponownie, chciałbym odkryć ukryte pola. Próbowałem użyć zmiennej globalnej, aby to osiągnąć, jednak nie mogłem sprawić, by działała poprawnie.

Oto, czego próbowałem:

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

Jakieś sugestie, co jest nie tak z tym kodem?

Neofile
źródło
1
Nie sądzę, aby można to zrobić bez jakiegoś rodzaju pamięci. Twoje zmienne JS zostaną wyczyszczone. Twój cały zakres zostanie poddany recyklingowi.
Dave Alperovich
Dlaczego nie umieścisz większości swojej strony w części „częściowej” i nie odświeżysz jej?
Dave Alperovich
Co to jest częściowe? Przepraszam, nie jestem tego świadomy.
Neophile
Czy rozważałeś przesłanie formularza przez AJAX i wyświetlenie pól po przesłaniu?
Dannyshaw
1
Czy możesz wyjaśnić, dlaczego chcesz odświeżyć stronę? Jeśli uda nam się tego uniknąć, możesz robić, co chcesz, jeśli będziesz tylko preventDefaultna submitwydarzeniu (zamiast tego, z clickktórego korzystasz).
Peleg

Odpowiedzi:

207

Ponieważ protokół HTTP jest bezstanowy, za każdym razem, gdy ładujesz stronę, użyje początkowych wartości tego, co ustawisz w JavaScript. Nie możesz ustawić zmiennej globalnej w JS i po prostu pozostawić tę wartość po ponownym załadowaniu strony.

Istnieje kilka sposobów na przechowywanie wartości w innym miejscu, aby można ją było inicjalizować podczas ładowania przy użyciu JavaScript


Ciąg zapytania

Podczas przesyłania formularza za pomocą GETmetody adres URL jest aktualizowany za pomocą ciągu zapytania ( ?parameter=value&something=42). Możesz to wykorzystać, ustawiając pole wejściowe w formularzu na określoną wartość. To byłby najprostszy przykład:

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

Podczas początkowego ładowania strony nie jest ustawiany żaden ciąg zapytania. Po przesłaniu tego formularza kombinacja namei valuedane wejściowe są przekazywane w ciągu zapytania jako clicked=true. Kiedy więc strona załaduje się ponownie z tym ciągiem zapytania, możesz sprawdzić, czy przycisk został kliknięty.

Aby odczytać te dane, możesz użyć następującego skryptu podczas ładowania strony:

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

( Źródło )

Możliwość korzystania z tego zależy od tego, jak obecnie działa Twój formularz, jeśli już używasz POST, może to być problematyczne.

Ponadto w przypadku większych zestawów danych jest to mniej niż optymalne. Przekazywanie ciągu znaków nie jest trudne, ale w przypadku tablic i obiektów danych prawdopodobnie powinieneś używać pamięci WWW lub plików cookie. Chociaż szczegóły różnią się nieco w różnych przeglądarkach, praktyczny limit długości identyfikatora URI wynosi około 2000 znaków


Pamięć internetowa

Wraz z wprowadzeniem HTML5 otrzymaliśmy również Web Storage, który umożliwia zapisywanie informacji w przeglądarce podczas ładowania strony. Jest to, localStoragektóre może zapisywać dane przez dłuższy czas (o ile użytkownik nie wyczyści ich ręcznie) i sessionStoragektóre zapisuje dane tylko podczas bieżącej sesji przeglądania. Ta ostatnia jest przydatna w tym przypadku, ponieważ nie chcesz, aby „kliknięto” było ustawione na prawdę, gdy użytkownik wróci później.

Tutaj ustawiłem pamięć na zdarzenie kliknięcia przycisku, ale możesz również powiązać go z przesłaniem formularza lub cokolwiek innego.

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

Następnie po załadowaniu strony możesz sprawdzić, czy jest ustawiona za pomocą tego:

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

Mimo że ta wartość jest zapisywana tylko podczas tej sesji przeglądania, może być konieczne zresetowanie jej wcześniej. Aby to zrobić, użyj:

sessionStorage.removeItem('clicked');

Jeśli chcesz zapisać obiekt lub tablicę JS, powinieneś przekonwertować to na łańcuch. Zgodnie ze specyfikacją powinno być możliwe zapisywanie innych typów danych, ale nie jest to jeszcze poprawnie zaimplementowane w przeglądarkach.

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

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

Obsługa przeglądarek jest całkiem niezła, więc korzystanie z niej powinno być bezpieczne, chyba że musisz obsługiwać naprawdę stare / niejasne przeglądarki. Web Storage to przyszłość.


Ciasteczka

Alternatywą dla Web Storage jest zapisywanie danych w pliku cookie. Pliki cookie służą głównie do odczytu danych po stronie serwera, ale mogą być również używane wyłącznie do danych po stronie klienta.

Używasz już jQuery, co sprawia, że ​​ustawianie plików cookie jest dość łatwe. Ponownie używam clickzdarzenia tutaj, ale można go używać wszędzie.

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

Następnie podczas ładowania strony możesz odczytać plik cookie w następujący sposób:

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

Ponieważ pliki cookie utrzymują się między sesjami w Twoim przypadku, będziesz musiał je wyłączyć, gdy tylko zrobisz z nimi wszystko, co musisz. Nie chciałbyś, aby użytkownik wrócił dzień później i nadal był clickedustawiony na true.

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

(sposób ustawiania / odczytywania plików cookie inny niż jQuery można znaleźć tutaj )

Osobiście nie użyłbym pliku cookie do czegoś prostego, jak zapamiętywanie stanu kliknięcia, ale jeśli ciąg zapytania nie jest opcją i musisz obsługiwać naprawdę stare przeglądarki, które nie obsługują sessionStorage, to zadziała. Powinieneś to zaimplementować najpierw ze sprawdzeniem sessionStorage i tylko jeśli to się nie powiedzie, użyj metody cookie.


nazwa.okna

Chociaż wydaje mi się, że to hack, który prawdopodobnie powstał przed localStorage / sessionStorage, możesz przechowywać informacje we window.namewłaściwości:

window.name = "my value"

Może przechowywać tylko ciągi znaków, więc jeśli chcesz zapisać obiekt, musisz go zdefiniować, tak jak w powyższym localStorageprzykładzie:

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

Główna różnica polega na tym, że te informacje są zachowywane nie tylko w przypadku odświeżania stron, ale także w różnych domenach. Jest jednak ograniczone do bieżącej karty, w której się znajdujesz.

Oznacza to, że możesz zapisać pewne informacje na swojej stronie i tak długo, jak użytkownik pozostaje na tej karcie, możesz uzyskać dostęp do tych samych informacji, nawet jeśli przeglądał inną witrynę iz powrotem. Generalnie odradzałbym używanie tego, chyba że musisz faktycznie przechowywać informacje z wielu domen podczas jednej sesji przeglądania.

Stephan Muller
źródło
9
Ugh, dopiero po napisaniu przeczytałem twój opis nagrody, który mówił „bez ciasteczek i lokalnego przechowywania”. Zachowam ten komentarz bez zmian dla innych, którzy mogą go potrzebować, ale myślę, że wystarczy użyć ciągu zapytania.
Stephan Muller
1
Zasadniczo używam już localStorage w wielu przypadkach dla mojej aplikacji internetowej i chciałbym uniknąć używania zbyt wielu zmiennych localStorage. Jednak podoba mi się pomysł usunięcia elementu localStorage, gdy skończę z nim. To było coś, o czym nie pomyślałem, używając mojej zmiennej localStorage.
Neophile
3
W przypadku żądania postu możesz zmodyfikować akcję -atrybut $ ("# formid"). Attr ("action", url + "& clicked = 1"), a także wykryć GET lub POST z $ ("# formid"). Attr ( „metoda”), ale może nie rozwiązać problemu z
ponownym
2
@TheNewbie Minęło trochę czasu, odkąd napisałem tę odpowiedź, ale właśnie dodałem nową opcję ( window.name). Może po prostu zrobić dokładnie to, czego potrzebujesz, bez używania plików cookie / localStorage.
Stephan Muller
1
Chciałem dodać, że pamięć lokalna i sesyjna nie są całkowicie niezawodne w nowszych przeglądarkach. Zwykle istnieje powrót do window.name.
JavaScript,
5

Spróbuj wykorzystać $.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>

gość271314
źródło
1

Używanie localeStoragelub sessionStoragewydaje się być najlepszym rozwiązaniem.

Zamiast zapisać clickedzmienną w zasięgu globalnym, zapisz ją w ten sposób:

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
źródło
Nie zamierzam najlepiej używać localstorage ani sessionStorage.
Neophile
-5

Możesz spróbować tego:

 $("input[type='submit'][value='Search']").click(function(){
     form.act.value='detailSearch'; 
     clicked = true;  
     return true;
});
renakre
źródło
Po ponownym załadowaniu strony nadal kliknięta wartość jest fałszywa.
Neophile
1
@TheNewbie myślisz, że możesz przekazać ciąg zapytania? przy odświeżaniu strony obecne podejście nie będzie działać.
renakre