web-dev-qa-db-ja.com

ページの読み込み間で変数を保持する

フォームの送信ボタンの押下をキャプチャしようとしています。フォームが送信されると、ページが更新され、いくつかの非表示フィールドが表示されます。フォームが以前に送信されたかどうかをキャプチャし、リロード時に送信された場合、非表示フィールドを再表示したいと思います。グローバル変数を使用してこれを達成しようとしましたが、適切に機能させることができませんでした。

ここに私が試したものがあります:

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

このコードの何が問題になっていますか?

78
Neophile

HTTPはステートレスなので、ページを読み込むたびに、JavaScriptで設定したものの初期値が使用されます。 JSでグローバル変数を設定して、ページを再度ロードした後にその値を維持することはできません。

JavaScriptを使用してロード時に値を初期化できるように、値を別の場所に保存できる方法がいくつかあります


クエリ文字列

GETメソッドを使用してフォームを送信すると、URLはクエリ文字列(?parameter=value&something=42)で更新されます。これを利用するには、フォームの入力フィールドに特定の値を設定します。これは最も簡単な例です:

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

ページの初期ロードでは、クエリ文字列は設定されていません。このフォームを送信すると、入力のnameおよびvalueの組み合わせがclicked=trueとしてクエリ文字列に渡されます。そのため、そのクエリ文字列を使用してページが再度読み込まれると、ボタンがクリックされたかどうかを確認できます。

このデータを読み取るには、ページの読み込み時に次のスクリプトを使用できます。

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

ソース

これを使用できるかどうかは、フォームが現在どのように機能しているかによって異なります。すでにPOSTを使用している場合、これは問題になる可能性があります。

さらに、大規模なデータセットの場合、これは最適ではありません。文字列を渡すことは大したことではありませんが、データの配列やオブジェクトには、おそらくWebストレージまたはCookieを使用する必要があります。詳細はブラウザによって少し異なりますが、URIの長さの実際的な制限は 2000文字 です


Webストレージ

HTML5の導入により、Webストレージも利用できるようになりました。これにより、ページをロードするたびに情報をブラウザーに保存できます。 (ユーザーが手動でデータを消去しない限り)長期間データを保存できるlocalStorageと、現在のブラウジングセッション中にのみデータを保存するsessionStorageがあります。後者は、ユーザーが後で戻ってきたときに「クリック」をtrueに設定したままにしたくないため、ここで役立ちます。

ここでは、ボタンのクリックイベントでストレージを設定しますが、フォーム送信などにバインドすることもできます。

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

次に、ページをロードするときに、これを使用して設定されているかどうかを確認できます。

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

この値はこのブラウジングセッション中にのみ保存されますが、以前にリセットしたい場合があります。これを行うには、次を使用します。

sessionStorage.removeItem('clicked');

JSオブジェクトまたは配列を保存する場合は、文字列に変換する必要があります。仕様によると、他のデータ型を保存することは可能ですが、これはまだブラウザー間で正しく実装されていません。

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

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

ブラウザのサポートは かなり素晴らしい なので、本当に古い/あいまいなブラウザをサポートする必要がない限り、これを使用しても安全です。 Webストレージは未来です。


Cookies

Web Storageの代替手段は、データをCookieに保存することです。 Cookieは主にサーバー側のデータを読み取るために作成されますが、純粋にクライアント側のデータにも使用できます。

すでにjQueryを使用しているため、Cookieの設定は非常に簡単です。繰り返しますが、ここではclickイベントを使用していますが、どこでも使用できます。

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

次に、ページの読み込み時に、次のようにCookieを読み取ることができます。

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

Cookieはセッション間で保持されるため、必要な処理を行ったらすぐに設定を解除する必要があります。ユーザーが1日後に戻ってきて、clickedがtrueに設定されたままにしたくないでしょう。

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

(Cookieを設定/読み取る非jQueryの方法があります

私は個人的に、クリックされた状態を記憶するような単純なものにはCookieを使用しませんが、クエリ文字列がオプションではなく、sessionStorageをサポートしない本当に古いブラウザーをサポートする必要がある場合、これは動作します。最初にsessionStorageをチェックして実装し、それが失敗した場合のみcookieメソッドを使用してください。


window.name

これは、おそらくlocalStorage/sessionStorageの前に由来するハックのように思えますが、window.nameプロパティに情報を保存できます。

window.name = "my value"

文字列のみを保存できるため、オブジェクトを保存する場合は、上記のlocalStorageの例のように文字列化する必要があります。

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

主な違いは、この情報はページの更新だけでなく異なるドメインでも保持されることです。ただし、現在のタブに制限されています。

つまり、ページにいくつかの情報を保存でき、ユーザーがそのタブにいる限り、別のWebサイトを閲覧したり戻ったりしても同じ情報にアクセスできます。一般に、単一のブラウジングセッション中にクロスドメイン情報を実際に保存する必要がない限り、これを使用しないようにアドバイスします。

164
Stephan Muller

$.holdReady()history を利用してみてください

<script src="jquery.js" type="text/javascript"></script>
</head>
<body>
<form method="POST">
    <input type="text" name="name" value="" />
    <input type="submit" value="Search" />
    <input type="hidden" />
    <input type="hidden" />
</form>
<script type="text/javascript">
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>
</body>
5
guest271314

localeStorageまたはsessionStorageを使用するのが最善策のようです。

Globleスコープにclicked変数を保存する代わりに、次の方法で保存します。

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
    }

});
1
me_digvijay