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

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

ただいまの
回答率

90.53%

  • JavaScript

    19927questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • jQuery

    7996questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

  • Monaca

    1092questions

    「Monaca」はiOS、Android、Windows向けのアプリ開発に対応した、Cordovaベースのモバイルアプリ開発プラットフォームです。HTML5、JavaScriptといったWeb標準技術を用いてモバイルアプリ開発を行うことができます。

リロードした時に前に登録した要素を取得する

解決済

回答 1

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 308

rinneP2525

score 6

前提・実現したいこと

Monacaでアプリを作っています。
入力ボタンを押した際にtable bodyが増えていき、そこにinputから文字を入力しているのですが、inputボタンを押した際に実行される処理の途中から(表にlocalstorageの内容を出力するところ)再度同じ処理を実行したいのですが、同じコードを書くのはスマートじゃないと思って四苦八苦しています。
今のコードは一回ウインドウを更新して、その時に表を表示するようになればいいなと思って書いているのですが、うまくいきません。
何か手立てがあればご教授いただけたら幸いです。
初心者な質問で申し訳ないのですが、よろしくお願いいたします。

発生している問題・エラーメッセージ

ページをリロードするとtableが消えてしまう

該当のソースコード

/* ローカルストレージ設定 */
  var storage = localStorage;

  /* 履歴を保存 */
  $('#f1').on('submit', function (e) {
    e.preventDefault()
    var obj = {
      day: $("#day").val(),
      money: $("#money").val()
    }
    var i = Math.floor(Math.random() * 101);
    storage.setItem("datalist" + i, JSON.stringify(obj));

    /* 履歴を取得 */
    var str = storage.getItem("datalist" + i);
    var obj = JSON.parse(str);
    window.location.reload();
    $(document).ready(function () {

      /* いったんデータを全部消す */
      $("#list").empty();

      /* 全ての要素を取得する */
      for (i = 0; i < storage.length; i++) {
        var key = storage.key(i)
        storage.getItem("datalist" + i)
      }

      /* 登録されているkey, valueを順に取得して表示 */
      var v_id = "datalist" + i;
      var v_day = obj.day;
      var v_money = obj.money;
      if (v_day !== "" && v_money !== "") $('#t1 tbody').after($('<tr>').append($('<td>').html(v_day)).append($('<td>').text(v_money)).append($('<td>').html('<button class="remove">-</button>')));
      $("#day,#money").val("");
    });
  });
     <div class="main">
      <form id="f3">
        <div class="jougen">
          <p>課金上限</p>
          <p>
            <output id="rslt" form="settei" class="jogen">0</output></p>
        </div>
      </form>
      <div class="honbun1">
        <p>入力</p>
        <div style="display:inline-flex">
          <form id="f1">
            <div class="moji">
              <input type="date" name="day" id="day" class="day">
              <input type="number" class="money" name="money" id="money"><input type="submit" value="入力" class="kettei1">
            </div>
          </form>
        </div>
      </div>
      <div class="nokori">
        <p>今月の残り課金額</p>
        <p>
          <output name="result" >0</output></p>
      </div>
      <br>
      <form id="f2">
        <p>履歴</p>
        <div class="rireki">
          <table id="t1" border="1">
            <thead>
              <tr>
                <th hidden>id</th>
                <th width="30%">日付</th>
                <th width="50%">金額</th>
                <th width="20%">削除</th>
              </tr>
            </thead>
            <tbody id="list"></tbody>
          </table>
        </div>
      </form>
      <input type="button" value="クリア" id="clear">
    </div>
  </body>

試したこと

データを全部消す前で一回切って新しく$(document).ready( function()で始めた
→obj.dayなどが上から引っ張られずにデータが入ってこなかった

途中でリロードしてHTMLを取り込んだ後の処理を入れた
→現状。一瞬だけtableが現れて消える

追記:できました!

/* ローカルストレージ設定 */
    var storage = localStorage;
    let datalist_st = storage.getItem('datalist');
    /* 入力ボタンを押すとデータを取得する */
    $(function() {
        const day = $('#day').val();
        const money = $('#money').val();

        displayList();
        $('#f1').on('submit', function(e) {

            e.preventDefault()

            if ($('#day').val() === '') {
                alert('日付を入力してください');
                return false;
            }
            if ($('#money').val() === '') {
                alert('金額を入力してください');
                return false;
            }


            if (datalist_st != null) {
                datalist = JSON.parse(datalist_st);
            } else {
                datalist = [];
            }

            const row_data = {
                day: $('#day').val(),
                money: $('#money').val()
            };

            datalist.push(row_data);

            storage.setItem('datalist', JSON.stringify(datalist));
            $("#day,#money").val("");
            window.location.reload();
        });
    });

    function displayList() {
        if (datalist_st != null) {
            datalist = JSON.parse(datalist_st);
        } else {
            datalist = [];
        }
        for (i = 0; i < datalist.length; i++) {
            let record_tr = $('<tr></tr>', {
                id: 'row_' + i
            });
            const td_id = $('<td></td>', {
                hidden: 'hidden',
                html: i
            });
            const td_day = $('<td></td>', {
                html: datalist[i].day
            });
            const td_money = $('<td></td>', {
                html: datalist[i].money
            });
            const remove_btn = $('<button></button>', {
                html: '-',
                type: 'button',
                class: 'remove'
            });
            remove_btn.attr('data-id', i);
            const td_remove = $('<td></td>', {
                html: remove_btn
            });
            record_tr.append(td_id);
            record_tr.append(td_day);
            record_tr.append(td_money);
            record_tr.append(td_remove);
            record_tr.append(td_remove);
            $('#list').append(record_tr);
        }
        /* 選択した列のデータを削除 */
        $("#list").click(function() {
            let storageItem = JSON.parse(storage.getItem('datalist'));
            const id = 'data-id';
            const index = storageItem.findIndex((v) => v.id === id);
            const removeid = storageItem.splice(index, 1);
            storage.setItem('datalist', JSON.stringify(storageItem));
            window.location.reload();
        });
    }


    /*  全てのデータを削除 */
    $("#clear").click(function() {
        storage.clear();
        window.location.reload();
    });
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

質問への追記・修正、ベストアンサー選択の依頼

  • mts10806

    2019/04/16 11:03 編集

    ↑で私が提示したhtml整形サービス
    http://u670.com/pikamap/htmlseikei.php
    でも構文チェックができるのでそちらで確認してみてください(構文チェック機能のあるエディタ使うのが確実ですが)

    キャンセル

  • mts10806

    2019/04/16 11:05

    >現在のhtmlでも最初の </form>と最後の</div>が開始タグがないようです。
    というより</form>を</div>にして最後の</div>を削除するか</form>を削除するか、ですかね。
    レイアウトによるのでそこは確認してみてください。

    キャンセル

  • rinneP2525

    2019/04/16 11:19

    これで構文チェックは問題なかったのですが…大丈夫でしょうか…

    キャンセル

回答 1

checkベストアンサー

+2

$(document).ready(function() { });は「ドキュメント読み込み時」のイベントを取る機能になるのでonsubmitの中に入っているのはおかしいです。
毎回押さないとこの中のイベントが発生しません。

むしろ、セレクタ.on()のイベントをdocument.readyの中に入れるべき。
で、「データを読みだしてくる」を関数にしておくと有用です。

あと、終端;があったりなかったりしていますが、間違いを起こさないために「終端すべてにつける」癖をつけておくと良いと思います。


そこだけ修正したJavaScriptのコードは下記。

/* ローカルストレージ設定 */
var storage = localStorage;

$(function() {
    displayList();
    /* 履歴を保存 */
    $('#f1').on('submit', function(e) {
        e.preventDefault()
        var obj = {
            day: $("#day").val(),
            money: $("#money").val()
        }
        var i = Math.floor(Math.random() * 101);
        storage.setItem("datalist" + i, JSON.stringify(obj));

        /* 履歴を取得 */
        var str = storage.getItem("datalist" + i);
        var obj = JSON.parse(str);
        window.location.reload();
    });
});

function displayList(){
    /* いったんデータを全部消す */
    $("#list").empty();

    /* 全ての要素を取得する */
    for (i = 0; i < storage.length; i++) {
        var key = storage.key(i);
        storage.getItem("datalist" + i);
    }

    /* 登録されているkey, valueを順に取得して表示 */
    var v_id = "datalist" + i;
    var v_day = obj.day;
    var v_money = obj.money;
    if (v_day !== "" && v_money !== "") $('#t1 tbody').after($('<tr>').append(
        $('<td>').html(v_day)).append($('<td>').text(v_money)).append($('<td>')
        .html('<button class="remove">-</button>')));
    $("#day,#money").val("");
}

切り分けると色々と見えてきます。


リロードするなら取得するのは意味がない

        var str = storage.getItem("datalist" + i);
        var obj = JSON.parse(str);
        window.location.reload();


変数なのでリロードしてしまっては値を保持しません。


storageのlength。。。?

    for (i = 0; i < storage.length; i++) {


LocalStorageをこのデータのためだけに使うのでしたらこれでも良いかもしれませんが、このやり方はお世辞にも良いとは言えません。
LocalStorageはドメイン内で共有されます。同じアプリケーション内の他の用途でLocalStorageを使う場合もあるかもしれません。
その際にこのやり方だと「LocalStorageの情報全て回す」ことになります。


下記は何がしたいのかわかりません。

    for (i = 0; i < storage.length; i++) {
        var key = storage.key(i); // ローカルスコープでkeyを保持してて使ってない
        storage.getItem("datalist" + i); //getItem()の結果をどこにも保持していない

ランダムで振っているのは大丈夫?

        var i = Math.floor(Math.random() * 101);
        storage.setItem("datalist" + i, JSON.stringify(obj));


そのためstorage.lengthをとっているのかもしれませんが結構煩雑になっています。

そもそもランダムに振る必要があるのか?そこも考える必要があります。
今後、行の削除、行の更新とか発生した際に、この運用がやりやすいかどうか?です。

単に追記していくだけなら良いでしょうけど・・・。

上記踏まえたうえで、自分なりにコードを(あまり元のコードのやり方を崩さずに)書いてみました。

私ならこう書く、というのを作ってみました。
おおよそ動くとは思いますが、きちんと全て理解してから使うようにしてください。
一応、それなりに動くコードなので「できた」と思い込んでしまってはきっとここから何も対応できなくなりますので、コードを確認したうえで不明な点はこの回答のコメント欄にて解決するようにしてください。

var storage = localStorage;
let datalist_st = storage.getItem('datalist');
$(function() {
    displayList();
    $('#f1').on('submit', function(e) {

        e.preventDefault()

        if(datalist_st != null){
            datalist = JSON.parse(datalist_st);
        }else{
            datalist = [];
        }
        const row_data = {
            day: $('#day').val(),
            money: $('#money').val()
        };
        datalist.push(row_data);
        storage.setItem('datalist', JSON.stringify(datalist));
        $("#day,#money").val("");
        window.location.reload();
    });
});

function displayList(){
    if(datalist_st != null){
        datalist = JSON.parse(datalist_st);
    }else{
        datalist = [];
    }
    for (i = 0; i < datalist.length; i++) {
        let record_tr = $('<tr></tr>',{id:'row_'+i}); 
        if(datalist[i].day != '' && datalist[i].money != ''){
            const td_id = $('<td></td>',{hidden:'hidden',html:i});
            const td_day = $('<td></td>',{html:datalist[i].day});
            const td_money = $('<td></td>',{html:datalist[i].money});
            const remove_btn = $('<button></button>',{html:'-',type:'button',class:'remove'});
            remove_btn.attr('data-id',i);
            const td_remove = $('<td></td>',{html:remove_btn});
            record_tr.append(td_id);
            record_tr.append(td_day);
            record_tr.append(td_money);
            record_tr.append(td_remove);
            record_tr.append(td_remove);
            $('#list').append(record_tr);
        }
    }
}

作ってて思った。
表示時にday,moneyのデータ有無確認するんじゃなくて、登録するときに入力ない場合はそもそも入力チェックに引っ掛けて保存させないようにしたほうが動作として自然では?

そこはやってみてください。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2019/04/16 12:12

    ありがとうございます!!
    自分でも「大丈夫かこれ…?」と思いながら使っているものをズバズバ指摘されていてほんと申し訳ないです…
    >リロードするなら取得するのは意味がない
    確かにそうですね…これは四苦八苦して無理やりつけた感じなのでリロードしないようにします
    >storageのlength。。。?
    これは説明サイトにあるものを理解せずこのままコピってました…
    ストレージの情報を全部取得するから全部回していいと汗
    >下記は何がしたいのかわかりません。
    ストレージの内容をdatalist + iの部分だけ取得できないかと模索した結果でした…
    >ランダムで振っているのは大丈夫?
    順番に振るほうが簡単だったのですがうまくいかなくてランダムにしてました。
    勉強して順番にしてみます

    >表示時にday,moneyのデータ有無確認するんじゃなくて、登録するときに入力ない場合はそもそも入力チェックに引っ掛けて保存させないようにしたほうが動作として自然では?
    確かに…!なぜ表示時にしてたんでしょう…。
    やり直してみます!


    以上を踏まえて書いていただいたコードをじっくり読んでからまたわからないことがあったらコメントさせていただこうと思います。
    理解するのに時間がかかるためもしかしたら数日かかるかもしれませんがよろしくお願いいたします…

    キャンセル

  • 2019/04/16 12:23

    どこかからコードを持ってくるのは結構なのですが、自身のコードに持ってくる際は「流れに沿っているか」は一考の必要があります。
    もちろん今回の回答のコードもそうですね。そのまま動くからと過信しすぎてはいけません。
    一応、「削除」のことも加味してデータ入れこんではいますが、使えるかどうかは確認してください。
    あくまで回答のコードは「他人が勝手に作った他人のコード」です。

    > 確かに…!なぜ表示時にしてたんでしょう…。
    「自然に」と書きましたが、データの観点から見ると無駄であることが分かります。
    表示されない=削除ボタンも設置されない ので削除する機会がなくなります。
    保存できるデータ量は有限なので、そもそも参照されないデータを保存する意味はないです。
    「バリデーション」の概念は念頭においておきましょう。

    キャンセル

  • 2019/04/16 12:30

    >どこかからコードを持ってくるのは結構なのですが、自身のコードに持ってくる際は「流れに沿っているか」は一考の必要があります。
    consoleをみてエラーが出ないからとりあえず入れとけーとしていました…反省点ですね…。

    >「自然に」と書きましたが、データの観点から見ると無駄であることが分かります
    保存されないならば削除する必要もないんですよね…。なんか調べてる時にそういうコードをみた気がするので参考にしつつ頑張ってみます

    キャンセル

  • 2019/04/16 12:39

    データもコードも同じで、無駄なコード入れてもそれだけファイルの容量喰うだけでその積み重ねが速度低下を招くので必ず「意味あるコードのみ」を入れるようにしてください。
    consoleについても確認終わったら削除すべきです。

    > なんか調べてる時にそういうコードをみた気がするので参考にしつつ頑張ってみます
    他人のコードに頼るのではなく、考えてみましょう。論理的思考は考えないと育ちませんし、他人のコードありきになってしまうとまたちぐはぐな、自分の手におえないコードができあがって、質問で丸投げすることになります。
    自分でできたらそれが一番速いのは当然のことですので、自分で考えて組み込む割合を少しずつでも大きくしていきましょう。

    キャンセル

  • 2019/04/16 12:39

    一気に全部やろうとするとパンクするので
    「入力されたら登録しない」から。「入力されたら入力エラーにする」はそれができてからです。

    キャンセル

  • 2019/04/16 14:21

    ありがとうございます。
    varがletやconstになっただけで狼狽えてしまうのでまだまだですね…
    datalist.push(row_data);
    これでdatalistのvalueを増やしていってるのですね。すごく勉強になります。

    質問で申し訳ないのですが、
    let record_tr = $('<tr></tr>',{id:'row_'+i});
    これの'row_'とは何を指しているのでしょうか?
    これにiをプラスしてidを振っているというのはなんとなくわかるのですが…

    キャンセル

  • 2019/04/16 14:37

    >varがletやconst
    いずれにしても変数の宣言ですね。違いは調べると詳しい解説記事はでてきますが、要は「宣言後、変数の情報が変更されるかどうか」で使い分けます。より厳格なコーディングをしたい場合なので慣れないうちはひとまずvarでも問題ないです。

    >これでdatalistのvalueを増やしていってるのですね。

    データベースの考え方としては「ひとつの配列のデータ」を1要件として扱うため、登録先のstorageのキーを増やすのではなく、1キーにまとめてます。

    >これの'row_'とは何を指しているのでしょうか?

    行番号としてtrにid振ってるだけです。rowは日本語で「行」。それだけの話です。数字始まりでidやclassの名前はつけられないので。
    扱うデータをきちんと扱えばリロードせずともtableに表示するデータを増やしたり減らしたりできるので、そこを見越した対応です。

    キャンセル

  • 2019/04/16 15:30

    ありがとうございます。

    >ひとまずvarでも問題ないです。
    慣れないと次に進めないので慣れれるように頑張ります!

    >「ひとつの配列のデータ」を1要件として扱うため
    なるほど…確かにそっちの方が良いですね…
    そっくりコピーするのが嫌だったので自分のを弄っていたのですが、自分のではその考え方から外れているので、理解できてからいただいた回答のコードをいじろうと思います

    >行番号としてtrにid振ってるだけです
    ありがとうございます…他にrow_が出てきている場面がなかったので混乱してしまいました。
    これを使って列のデータを消したりできるということですね!

    キャンセル

  • 2019/04/16 15:35

    >列のデータを消したりできるということですね!

    理解は合ってますが考え方は逆で、「見越した情報を準備した」です。
    「できるようになった」のではなく「できるようにした」です。
    一意の名称をつけておくことで様々な用途に対応しやすくしたわけです。設計みたいなものです。
    コードベースで考えようとするとつまずきやすくなるので、あくまで設計ベースで考えること。
    設計とか表現すると堅苦しくなるので、手順を箇条書きするとかでもいいです。コードへの反映がぐっと楽になります

    キャンセル

  • 2019/04/16 15:48

    ありがとうございます。
    1列ずつ削除する方法も模索していたのでこれを利用してできるようにやってみます。
    手順を箇条書きですね…確かに頭の中でしか設計できておらず、グズグズの状態でした。
    一度書き起こしてみます!

    キャンセル

  • 2019/04/18 16:23

    ありがとうございます。日数が経ってしまいましたが回答いただいたコードを自分なりに理解し、列の削除機能と全てクリア機能、入力する際に入力フォームに値が入っていないとアラートを出す機能をつけました。

    まだまだ理解できてないことも多いのでJavasprictの本も買って勉強中です。

    ご回答本当にありがとうございます!

    キャンセル

  • 2019/04/18 16:35

    素晴らしいですね。最初の質問の時からすると、これだけのコードでそこまでできたのは大したものだと思います。
    組み方や考え方は他の場面でも活用できるので、がんばってください

    キャンセル

  • 2019/04/18 16:37

    mts10806様を含め回答をいただいたおかげです!
    ありがとうございます!

    キャンセル

  • 2019/04/18 16:44

    いえいえ。少しでも助けになれたのなら幸いです

    キャンセル

同じタグがついた質問を見る

  • JavaScript

    19927questions

    JavaScriptは、プログラミング言語のひとつです。ネットスケープコミュニケーションズで開発されました。 開発当初はLiveScriptと呼ばれていましたが、業務提携していたサン・マイクロシステムズが開発したJavaが脚光を浴びていたことから、JavaScriptと改名されました。 動きのあるWebページを作ることを目的に開発されたもので、主要なWebブラウザのほとんどに搭載されています。

  • jQuery

    7996questions

    jQueryは、JavaScriptライブラリのひとつです。 簡単な記述で、JavaScriptコードを実行できるように設計されています。 2006年1月に、ジョン・レシグが発表しました。 jQueryは独特の記述法を用いており、機能のほとんどは「$関数」や「jQueryオブジェクト」のメソッドとして定義されています。

  • Monaca

    1092questions

    「Monaca」はiOS、Android、Windows向けのアプリ開発に対応した、Cordovaベースのモバイルアプリ開発プラットフォームです。HTML5、JavaScriptといったWeb標準技術を用いてモバイルアプリ開発を行うことができます。