質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.12%

各ボタンから追加した各テキストエリアをlocalStorageで保存・削除を実行したい

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,164

suisuin

score 15

各ボタンから追加した各テキストエリアをlocalStorageで保存・削除を実行したい

ワードプレスでページ製作をしています。javaに関しては素人で検索した素材をよく利用しています。

今回、複数のテキストエリア生成ボタンを用意し、追加した要素&テキストエリアの内容を保存するために検索しヒットした情報を実行、微調整、繋ぎ合わせと素人ならではで試行錯誤しております。

localStorageを利用して次のことを実現したいです。
(1)appendで追加した<li><texterea><button>~をブラウザの更新時に消えないように保存する
(2)appendで追加した各テキストエリアの内容を(各々or一括)保存する
(3)appendで追加した<li>を削除する
(4)各テキストエリアで保存した内容を全てクリアにする
現状、追加は出来ても要素&テキストエリアの保存・削除ができません。

ただいま検証しているコードが下記になります。

各ボタンでテキストエリアを追加するコード

<button id="ma">button1</button>
<button id="sa">button2</button>
<button id="ka">button3</button>
    <ul id="list">
    </ul>
</li>
</ul>

<script>

      $(function() {
        $("#ma").click(function() {
        $("#list").append('<textarea id="text1" class="text1"></textarea><button id="save1">保存</button><button id="delete1"  onClick="history.go(0)">削除</button>');
        });

        $("#sa").click(function() {
        $("#list").append('<textarea id="text2" class="text2"></textarea><button id="save2">保存</button><button id="delete2" onClick="history.go(0)">削除</button>');
        });

        $("#ka").click(function() {
        $("#list").append('<textarea id="text3" class="text3"></textarea><button id="save3">保存</button><button id="delete3" onClick="history.go(0)">削除</button>');
//とりあえず3個ですが実際はは10個以上作る予定です。
        });
     });

<script>

上記のコードをもとに、localStorageの指示をあてはめようと苦戦しています。

追加された要素&テキストエリアをlocalStorageで保存・削除

以下、複数のテキストのエリアの保存ができたスクリプトです。
これをうまく上記のスクリプトに組み合わせられれば良いのですが、そもそも見当違いかもしれません。

$(function(){
    $("#list .text1").val(window.localStorage.getItem("text1"));
    $("#list .text2").val(window.localStorage.getItem("text2"));
    $("#list .text3").val(window.localStorage.getItem("text3"));

});

$("#save1").click(function(){
    window.localStorage.setItem('text1',  $("#list .text1").val());
    alert("データ1を保存しました。");
});

$("#save2").click(function(){
    window.localStorage.setItem('text2',  $("#list .text2").val());
    alert("データ2を保存しました。");
});

$("#save3").click(function(){
    window.localStorage.setItem('text3',  $("#list .text3").val());
    alert("データ3を保存しました。");
});


$("#delete").click(function(){
    window.localStorage.clear();
    $("#textarea1").val('');
    $("#textarea2").val('');
    $("#textarea3").val('');
    alert("データを全て削除しました。");
});


$("#delete1").click(function(){
window.localStorage.removeItem('text1', $("list").val());
    alert("データ1を削除しました。");
});

$("#delete2").click(function(){
window.localStorage.removeItem('text2', $("#list").val());
    alert("データ1を削除しました。");
});

$("#delete3").click(function(){
window.localStorage.removeItem('text3', $("#list").val());
    alert("データ3を削除しました。");
});

localStorageは文字列の保存ができないため、HTMLなどはオブジェクトに変換し保存ということでいろいろコードを当てはめたのですが保存できず。なのでHTMLは置いといて各ボタンからテキストエリアのみを追加、さらにテキストエリアの内容の保存を試みたりしたのですがうまくいきません。

どうかご教授くださいますようよろしくお願いいたします。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

checkベストアンサー

+2

まず初めに、これはlocalStorageに保存ができないのではなく
クリックイベントが付与できていないのが原因です。

#save(n)に対するclickイベントがdocument.readyのタイミングで定義されていますが
#save(n)はbuttonをクリックした際に追加される要素です。つまり、document.readyの段階ではページ上に存在していない要素です。
そのため、例え.on('click', fun)で定義しようと、そのイベントは付与されません。(alertが実行されないのはその為です)
正しくは、append()したタイミングで.on('click', fun)を行う必要があります。

//Ex.
$("#list").append('<textarea id="text1" class="text1"></textarea><button id="save1">保存</button><button id="delete1"  onClick="history.go(0)">削除</button>');
$('#save1').on('click', function(){
  //クリック時の処理
});

 
とはいえ、この要素ごとにいちいち一つづつイベントを作成、付与していくのはあまりにも冗長かつ
無駄にメモリを使用するので、親要素でイベント管理するほうが良いかなと思います。

そこで、まずはHtmlから少し改善して

<!--各ボタンに対して共通クラスを付与。(ここでは.butoon)-->
<button id="ma" class="button">button1</button>
<button id="sa" class="button">button2</button>
<button id="ka" class="button">button3</button>
    <ul id="list">
    </ul>
//コード内でconst,letを使用していますが、そのままvarに置き換えてもOKです。
$(function() {
    const wrapper = $('#list');
    //documentではなく、上記Htmlの親要素のidでもOK
    $(document).on('click', '.button, .save, .delete', function(){ //$(element)以下の.button, .save, .deleteを持つ要素すべてに対してクリックイベントを(この方法は後から追加された要素に対しても有効)
        let elClass = $(this).attr('class') //クリックされた要素のクラス名を取得
        let num = $('.'+elClass).index(this); //その要素が同一クラスを持つ要素の中で何番目か取得
        let n = num + 1;

        if( $(this).hasClass('button') ){ //.buttonなら
            wrapper.append('<textarea id="text'+ n +'" class="text"></textarea><button id="save'+ n +'" class="save">保存</button><button id="delete'+ n +'" class="delete" onClick="history.go(0)">削除</button>'); //追加されるtextarea、保存、削除用ボタンも共通クラスに変更
        }else if( $(this).hasClass('save') ){ //.saveなら
            let val = $("#list .text").eq(num).val();
            localStorage.setItem('text'+n , val ); //window.は無くてOK
            alert("データ"+n+"を保存しました。");
        }else{ //.deleteなら
            localStorage.removeItem('text'+n); // removeItem()の引数はkeyのみ(valueは不要)
            alert("データ"+n+"を削除しました。");    
        }
    });
});


getItem()の箇所と
localStorage.clear()の箇所はいまいちどのようにしたいのかピンとこなかったので割愛しています。

buttonを押した時に追加されるtextarea内に、localStorage内に対応するデータが保存されていた場合
その内容を表示する、というのであれば上記コード内のif( $(this).hasClass('button') ){ ...}の箇所へ

wrapper.append('<textarea〜);
if(localStorage.getItem('text'+n)){
    $('#text'+n).val(localStorage.getItem('text'+n))
}


とでもしてやれば良いでしょう。

削除ボタンに対してhistory.go(0)がonClick属性で付与されているため、
削除ボタンを押すと毎回リロードされてしまうかたちになりますが、これも意図通りなのでしょうか?

また、#deleteという要素が質問のコード内に存在していないため
その要素へ設定したクリックイベントも割愛しています。


localStorageは文字列の保存ができないため

そんなことはありません。localStorageは文字列で保存されます。
(もしくはオブジェクト形式での保存のいずれかになります)

あと細かいことですが、JavaとJavaScriptは別言語ですので混同しないようにしておきましょう。

追記

イメージ説明
こちらの環境ではすべて保存ができていますが…。(リアルタイムでstorageへ追加されているのが確認できない場合あり。注:保存はされている=リロードすると保存できているのが確認可)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/21 19:33

    次のことでようやく成功しました。
    1. .buttonを変更
    2.提示頂いたjavascriptの6行目、データが保存時のコードの4行目にセミコロンを入れる。
    3. if( $(this).hasClass('button') ){ ...}の箇所へ「 localStorage.setItem("list", $("#list").html());」を追記

    3は、片っ端から当てはめてみて試した結果です。ただ、意味はよく理解できてませんが
    何においても解決できました。ありがとうございました。

    キャンセル

  • 2017/01/21 20:05

    ええと…
    if( $(this).hasClass('button') ){ ...}の箇所へlocalStorageへの保存処理を入れると
    回答文画像で言う所の「button1,2,3」をクリックした時にtextarea内の内容が保存されるようになります。
    「保存」ボタンをクリックした時にtextarea内の内容がlocalStorageへ保存されるようにしたいのではないのですか?
    「button1,2,3」をクリックした時に、へ仕様を変更されたのであればそれでいいのではないでしょうか。

    また、「 localStorage.setItem("list", $("#list").html());」では
    textareaを含むhtml要素(<textarea id="text(n)" class="text" /><button>...)といった内容をlocalStorageへ保存するということになるのでは?
    またkey名が重複しているのでどのボタンをクリックしても内容を上書きするということになるかと。

    それでうまく行っているのであれば、提示していただいている内容と実際の環境に差異があるか、こちらが質問の内容を勘違いをしているかかなと思います。

    キャンセル

  • 2017/01/22 18:25

    すみません。先に指摘の 勝手に追記した「localStorage.setItem("list", $("#list").html());」を削除した上で、各ボタンそれぞれの保存を確認できました。

    ただその前まで出来ていなかったことで、恐らくそれまで色々試していたコードが何か残っていて悪さをしていたのではと思います。

    目的については、仰るとおりです。textarea内の内容がlocalStorageへ保存したかったのですが、回答をいただき動作を確認していくうちに 「リロードしてもwrapper.appendで追加された内容表示を残せないか」と思い色々試してました。これも原因に含まれると思います。

    現状、ボタンをクリックしテキストエリアを追加 ⇒ 保存ボタンでテキストエリアの内容が保存 ⇒ リロードしたのちボタンをクリックすればテキストエリアの保存内容が確認できます。これをリロードしてもテキストエリアの表示を残したいと思いました。ただ当初の質問とは異なるのではと思いそこは触れずにいた次第です。 そこは自分で何とかできないかなと思い今挑戦しています。

    キャンセル

+1

$(document).on('click', '#save1', function(){
    window.localStorage.setItem('text1',  $("#list .text1").val());
    alert("データ1を保存しました。");
});

$(document).on('click', '#save2', function(){
    window.localStorage.setItem('text2',  $("#list .text2").val());
    alert("データ2を保存しました。");
});

$(document).on('click', '#save3', function(){
    window.localStorage.setItem('text3',  $("#list .text3").val());
    alert("データ3を保存しました。");
});


これでいかがでしょうか?

変更部分は
$("#save1").click(function(){

$(document).on('click', '#save1', function(){
に置き換えております。

少し気になって調べてみましたら、興味深い記事がありました。

jQueryのappendメソッドなどで後から追加した要素にclickイベントを設定するとクリックをしているのに動かないことがあります。
そういうときは、onメソッドを使うと解決できる

clickイベント(jQuery)の罠

私もこの問題で引っかかりそうでしたので大変勉強になりました。
頑張って開発を続けてくださいね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/19 20:13

    ありがとうございます。
    リンク先拝見し勉強させていただきました。
    指定のとおりに設定し、他もいろいろ触ったのですがおも通りに動かず今も頑張ってます!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.12%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる