pagebeforecreateのイベントで、getJSONしてから、listview("refresh")してたんですが、getJSONの結果をlocalStorageに突っ込んで、次回以降はlocalStorageから取れば良いよね。
と思ってた時期が僕にもありました。いや、今もそう思ってるんですが、ハマったので晒しておく。
元のコードはこんな感じでした。
$("#hoge").live("pagebeforecreate", function(event) { $.getJSON("sample.json") .success(handleHoge) .error(handleAjaxError); }); var handleHoge = function(data) { $.each(data.items, function(i, item) { $("<li></li>").text(i + ":" + item).appendTo("#listview"); }); $("#listview").listview("refresh"); };
getJSONが非同期なので、handleHogeも遅延して行われるために、jQueryMobileがページを組み立てた後にlistviewにDOMが弄られます。だから、listview("refresh")をしてあげないとちゃんとスタイルを適用してくれませんね。
で、getJSONの結果をlocalStorageにキャッシュしようとしたコードが次のようになります。
$("#hoge").live("pagebeforecreate", function(event) { var items = localStorage.getItem("items"); if (items) { handleHoge(JSON.parse(items)); return; } $.getJSON("sample.json") .success(function(data) { handleHoge(data.items); localStorage.setItem("items", JSON.stringify(data.items)); }).error(handleAjaxError); }); var handleHoge = function(items) { $.each(items, function(i, item) { $("<li></li>").text(i + ":" + item).appendTo("#listview"); }); $("#fuga").listview("refresh"); };
これ、初回のgetJSONした場合にはちゃんと動くのですが、2回目にlocalStorageにした場合は非同期じゃないので、listview("refresh")が出来ないって怒られます。
「Uncaught cannot call methods on listview prior to initialization; attempted to call method 'refresh'」ってエラーメッセージですね。
なもんで、listview("refuresh")するのは、非同期通信した時だけにしないとダメだよって話し。どうするかと言うと次の通り。
$("#hoge").live("pagebeforecreate", function(event) { var items = localStorage.getItem("items"); if (items) { handleHoge(JSON.parse(items)); return; } $.getJSON("sample.json") .success(function(data) { handleHoge(data.items); $("#fuga").listview("refresh"); // ここのあたりでリフレッシュする localStorage.setItem("items", JSON.stringify(data.items)); }).error(handleAjaxError); }); var handleHoge = function(items) { $.each(items, function(i, item) { $("<li></li>").text(i + ":" + item).appendTo("#listview"); }); //$("#fuga").listview("refresh"); ← ここではリフレッシュしない。 };
こうすることで、非同期で遅延した時だけlistview("refresh")をして、非同期通信しないで遅延しなかった時にはlistview("refresh")をしないようにしたんだよね、ってお話でした。
これが正しい方法なのか、もっと賢いやりかたがあるのかわからないです。
あったら教えてくだしあ。
最終的なコード
<!DOCTYPE html> <html lang="ja"> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> <title>サンプル</title> <script type="text/javascript" src="http://code.jquery.com/jquery-1.6.4.min.js"></script> <script type="text/javascript"> (function() { $("#second").live("pagebeforecreate", function(event) { var items = localStorage.getItem("items"); if (items) { handleHoge(JSON.parse(items)); return; } $.getJSON("sample.json") .success(function(data) { handleHoge(data.items); $("#listview").listview("refresh"); localStorage.setItem("items", JSON.stringify(data.items)); }).error(handleAjaxError); }); var handleHoge = function(items) { $.each(items, function(i, item) { $("<li></li>").text(i + ":" + item).appendTo("#listview"); }); }; var handleAjaxError = function(e, s) { alert("error!!" + e.status + ":" + s); }; })(); </script> <script type="text/javascript" src="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.js"></script> <link rel="stylesheet" href="http://code.jquery.com/mobile/1.0.1/jquery.mobile-1.0.1.min.css" /> </head> <body> <!-- main --> <section data-role="page" id="main"> <header data-role="header"> <h1>サンプル</h1> </header> <div data-role="content"> <a href="#second">次へ</a> </div> <footer data-role="footer"> <h4>サンプル</h4> </footer> </section> <section data-role="page" id="second"> <header data-role="header"> <a data-rel="back" data-role="button" data-icon="arrow-l">戻る</a> <h1>サンプル2</h1> </header> <div data-role="content"> <ul data-role="listview" id="listview"> </ul> </div> <footer data-role="footer"> <h4>サンプル2</h4> </footer> </section> </body> </html>