【35:localStorage】HTML5のlocalStorageでTODOリストを作る
プロジェクトNo.35:localStorage - DEMO
HTML5のWeb Storageの一つであるlocalStorageを使ってTODOリストを作ってみましたが、
今回は正直、結構はまりました。
そのバグトラッキングも含めてご紹介したいと思います。
新しく覚えた部分が多かったので少し長いです。
Web Storageとは
HTML5からWeb Storageという機能が追加されました。
Web Storageとはクライアントのディスク上に少量のデータを保存しておくためのストレージです。
Cookieと何が違うかというと、
- サイズ制限がない
- サーバーに送信されない
- 有効期限がない
- JavaScriptオブジェクトをそのまま保存できる
といった点があります。
特徴としては単純な「キー・バリュー」ストレージになっており、name:tanaka(key:value)という様に保存できます。
Web Storageには2種類あり、「ローカルストレージ」と「セッションストレージ」です。
これらの違いはデータの生存期間や有効範囲だけです。
今回、使うのは「ローカルストレージ」で、Webサイト毎にストレージを確保します。
同じページを別のウインドウで開いたり、ブラウザを終了して再表示したりしてもストレージの中身は永続されます。
ユーザーが明示的にストレージをクリアしない限り、データは永続します。
基本的な使い方
ストレージへの保存、取得、削除
HTML5の機能ですが、記述はJavaScript上に書いていきます。
HTMLのDOCTYPE宣言でHTML5を指定したら、
JavaScript上でlocalStorageというグローバル変数を使える様になります。
この変数に対して用意されているメソッドを使ってデータの入出力を行います。
いくつか方法はありますが、簡単な方法だと以下の様になります。
JavaScript
localStorage.setItem('memo','test'); // データセット localStorage.getItem('memo'); // データ取得 localStorage.removeItem('memo'); // データ削除 localStorage.clear(); // データ全削除
TODOリストを作る | 問題:ソートが上手くいかない
ローカルストレージを利用して、TODOリストを作ってみようとしました。
・・・が、あるバグに悩まされました。
当初のバグありのソースは以下の通り。
JavaScript(JQuery)
$(function () { var key = 0; // 初期読み込み // アルファベット順で格納されている(1,10,2,3,4,5 ...)ため意図したソートにならない・・・ for(key in localStorage){ // <li>を生成 cleateLi(localStorage.getItem(key)); } // 初期読み込み後にkeyを+1 key++; // 保存ボタン $('#save').click(function(){ // 入力フィールドの値を取得 var memo = $('#memo').val(); // 入力フィールドを空の場合は処理しない if(!memo) return; // ローカルストレージに保存 localStorage.setItem(key, memo); // <li>を生成 cleateLi(memo); // 入力フィールドを空にする $('#memo').val(''); // keyのカウントアップ key++; }); // <li>生成メソッド function cleateLi(value){ var li = $('<li>').html(value).addClass('todo').attr('data-todo',key); // 要素を末尾に追加 $('ul').append(li); // 動的に生成された要素<li>にonclickイベントを設定 $('ul').on('click', '.todo', function(){ localStorage.removeItem($(this).data('todo')); $(this).remove(); console.log($(this).data('todo')); }); } // 全消去ボタン $('#clear').click(function(){ localStorage.clear(); $('li').remove(); }); })
問題となったのはlocalStorageからデータを取得する際に、
中身が格納した順ではなくてkeyのアルファベット順で保存されているために意図したソートにならないという点です。
上記のプログラムでは保存ボタンを押下する度に、ローカルストレージのkeyを1から順に増やしてデータを保存しています。
key:(1,2,3,4,5,6,7,8,9,10)
保存時は良いのですが、ローカルストレージに一旦入ったデータを取得する時に、アルファベット順で格納されているので、
key:(1,10,2,3,4,5,6,7,8,9)
という風になってしまいました。
TODOリストを作る | 解決方法:配列に入れ替える
色々悩んで、辿り着いた解決策が以下になります。
$(function () { // localStorage.setItem('memo','test'); // データセット // localStorage.getItem('memo'); // データ取得 // localStorage.removeItem('memo'); // データ削除 // localStorage.clear(); // データ全削除 var list = []; // localStorageの内容をソートして格納するための配列 var i = 0; // listのアドレス番号及びlocalStorage保存時のkey // 初期読み込み // アルファベット順で格納されている(key:1,10,2,3,4,5 ...)ので、配列に格納してソートする for(var key in localStorage){ list[key] = localStorage.getItem(key); // console.log(list); } for(i in list){ // <li>を生成 console.log(i); cleateLi(list[i]); } // 初期読み込み後にiを+1 i++; // 保存ボタン $('#save').click(function(){ // 入力フィールドの値を取得 var memo = $('#memo').val(); // 入力フィールドを空の場合は処理しない if(!memo) return; // ローカルストレージに保存 localStorage.setItem(i, memo); // <li>を生成 cleateLi(memo); // 入力フィールドを空にする $('#memo').val(''); // iのカウントアップ i++; }); // <li>生成メソッド function cleateLi(value){ // 消去ボタン押下時に要素を特定するためにdata属性を利用する var li = $('<li>').html(value).addClass('todo').attr('data-todo',i); // 要素を末尾に追加 $('ul').append(li); // 動的に生成された要素<li>にonclickイベントを設定 $('ul').on('click', '.todo', function(){ localStorage.removeItem($(this).data('todo')); $(this).remove(); }); } // 全消去ボタン $('#clear').click(function(){ localStorage.clear(); $('li').remove(); }); })
ローカルストレージから取得したデータを配列に格納します。
格納する際に配列の番地も取得したデータを指定することで上手くいきました。
key:(1,10,2,3,4,5,6,7,8,9)
(list[1]=1, list[10]=10, list[2]=2...)
カスタムデータ属性
また今回の実装にあたり、いくつか新たな機能も使いました。
その1つがHTML5の機能のカスタムデータ属性です。
これはTODOリストを1件消去する際にクリックした要素を特定するために必要でした。
出力されるHTMLは以下の通りです。
HTML
<li class="todo" data-todo="1">1</li>
カスタムデータ属性を定義するには「data-」という接頭辞に持つ属性を要素に追加するだけです。
呼び出す時はJavaScriptの方から以下のように指定します。
JavaScript(JQuery)
$('ul').data.('todo');
動的に生成した要素に対してイベントを追加
今回のプログラムではTODOのリスト数は追加・削除できるため可変になっています。
静的な要素にクリックイベントを追加するには、最悪1つずつクリックした時の処理を記述すればよいのですが、
動的な要素の場合はそうはいきません。
そこで使えるのがonメソッドです。
書き方は以下の通り。
JavaScript(JQuery)
$('ul').on('click', '.todo', function(){ localStorage.removeItem($(this).data('todo')); $(this).remove(); });
イベントを追加したい要素の親要素に対してonメソッドを使用し、
イベント、対象の要素を指すセレクタ、コールバック関数という順に記述すればOKです。