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

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

ただいまの
回答率

90.00%

動的に追加したフォーム項目の合計を更新表示させたい

解決済

回答 2

投稿 編集

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

isshi

score 6

初心者です。
現在Djangoのformsetを利用したフォームを作成しています。
下記のHTMLでは追加ボタンを押下すると各入力項目のフォームを追加するJSを記述しています。
やりたいことは、動的に追加した項目(今回は時間(time)を対象)の合計を<span id="total"></span>に表示することです。
timeは分単位の入力で、30+40+90=160という形で和を求めたいと考えています。
追加した後のフォーム数を取得して、その数で繰り返し処理すること考えていましたがうまく更新されません。
JavaScriptやJQueryで処理する方法をご教示ください。

{% block title %}新規登録{% endblock title %}
<h4>{{ indate }}</h4>
<!doctype html>
<html lang="ja">
<head>
    <!-- Required meta tags -->
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

    <!-- Bootstrap CSS -->
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/css/bootstrap.min.css"
          integrity="sha384-9gVQ4dYFwwWSjIDZnLEWnxCjeSWFphJiwGPXr1jddIhOegiu1FwO5qRGvFXOdJZ4" crossorigin="anonymous">

    <title>テスト</title>
</head>

<body>
<style>
    table {
        table-layout: fixed;
    }
    .table tr td {
    border: 1px solid #eceeef;
    }
</style>
<form action="" method="POST">
    {{ form.management_form }}
    <table class="table">
        <thead>
        <tr>
            <th>大項目</th>
            <th>概要</th>
            <th>時間</th>
            <th>備考</th>
        </tr>
        </thead>

        <tbody id="answers">
        {% for fm in form %}
        {{ fm.id }}
        {{ fm.errors }}
        <tr>
            <td>{{ fm.LargeItem }}</td>
            <td>{{ fm.summary }}</td>
            <td>{{ fm.time }}</td>
            <td>{{ fm.memo }}</td>
        </tr>
        {% endfor %}
        </tbody>
    </table>

    <button id="add" type="button" class="btn btn-primary">追加</button>
    <button type="submit" class="btn btn-primary">送信</button>
    <a href="{% url 'mycalendar:month_with_schedule' %}" class="btn btn-primary">戻る</a>
    <br>
    <br>
    <span id="total"></span>です。
    {% csrf_token %}
</form>

<!-- Optional JavaScript -->
<!-- jQuery first, then Popper.js, then Bootstrap JS -->
<script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"
        integrity="sha384-q8i/X+965DzO0rT7abK41JStQIAqVgRVzpbzo5smXKp4YfRvH+8abtTE1Pi6jizo"
        crossorigin="anonymous"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.14.0/umd/popper.min.js"
        integrity="sha384-cs/chFZiN24E4KMATLdqdvsezGxaGsi4hLGOzlXwp5UZB1LY//20VyM2taTB4QvJ"
        crossorigin="anonymous"></script>
<script src="https://stackpath.bootstrapcdn.com/bootstrap/4.1.0/js/bootstrap.min.js"
        integrity="sha384-uefMccjFJAIv6A+rW+L4AHf99KvxDjWSu1z9VI8SKNVmz4sk7buKt/6v9KI65qnm"
        crossorigin="anonymous"></script>

<script>
$(function(){
  var current_count = parseInt($('input#id_form-TOTAL_FORMS').val());
  $('button#add').on('click', function(){
    var element = `<tr><td><select name="form-${current_count}-LargeItem" id="id_form-${current_count}-LargeItem">
        <option value="" selected>---------</option>
        <option value="test1</option>
        <option value="test2</option>
    </select>
    <td><input type="text" name="form-${current_count}-summary" maxlength="50" id="id_form-${current_count}-summary" /></td>
    <td><input type="number" name="form-${current_count}-time" value="0" id="id_form-${current_count}-time" /></td>
    <td><input type="text" name="form-${current_count}-memo" maxlength="50" id="id_form-${current_count}-memo" /></td></tr>`;
    $('tbody#answers').append(element);
    current_count += 1;
    $('input#id_form-TOTAL_FORMS').attr('value', current_count);
  });
});

function update_field(){
    var current_count = parseInt($('input#id_form-TOTAL_FORMS').val());
    var result = 0;
    for(var i = 0; i < current_count; i++){
        var result = $('#id_form-'+i+'-time').val() ;
        $('#total').text(result);
        }
}
$(function() {
  $('input[type="number"]').on('keyup change', function() {
    update_field();
  });
});

</script>
</body>
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • m.ts10806

    2018/08/08 06:20

    質問編集画面タイトル横にある「初心者アイコン」をご活用ください。「初心者」と質問で書くよりも伝わりますし、質問一覧に表示されるのでわかりやすくなります。

    キャンセル

  • m.ts10806

    2018/08/08 06:25

    $('#id_form-'+i+'-kosu').val()  ←これで入力した情報は正しく取得できていますか?また「時間」はどのような形式で入力されるのを想定していますか?ありえない時間(9999など)が入力された場合については今のところ考慮していないということでよろしいでしょうか。

    キャンセル

  • isshi

    2018/08/08 10:20

    初心者アイコンの件、承知しました。ありがとうございます。

    キャンセル

  • isshi

    2018/08/08 10:23

    $('#id_form-'+i+'-time').val()  の誤りでした。現状、id_form-5-timeの値のみ取得できているようです。また、時間は数値型で入力されることを想定しありえない時間等は今のところ考慮しておりません。別途バリデーション対応などを考えています。

    キャンセル

回答 2

+1

質問の重点がどこにあるかわかりません

単純にform内の特定の条件のついた要素を足すだけならこう

<script>
$(function(){
  $('.calc').on('click',function(){
    var v=$(this).closest('form').find('.hoge').map(function(){
      return parseInt($(this).val());
    }).get().reduce(function(x,y){return x+y});
    console.log(v);
  });
});
</script>
<form>
<input type="text" class="hoge" name="a" value="1"><br>
<input type="text" class="hoge" name="b" value="2"><br>
<input type="text" class="hoge" name="c" value="3"><br>
<input type="button" value="calc" class="calc">
</form>


それとも時間の和の仕方がわからないのでしょうか?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/08/08 11:04

    すみません、説明不足でした。
    時間とは工数(分)という意味で、
    35+40=75(分)
    130+240=370(分)
    という形です。

    キャンセル

  • 2018/08/08 11:12

    なるほど、すべてが分だけで整数値で処理されているのですね
    であれば最初に私が提示したものがまさに整数値の合計を計算する処理です

    キャンセル

  • 2018/08/09 00:02

    生成されるHTMLは以下のようになります。
    この場合、共通しているnumberに対してvalueの和をとるということでしょうか?
    <td><input type="text" name="form-0-summary" value="12344" maxlength="50" id="id_form-0-summary" /></td>
    <td><input type="number" name="form-0-time" value="1" id="id_form-0-kosu" /></td>
    <td><input type="text" name="form-0-memo" maxlength="50" id="id_form-0-memo" /></td>

    <td><input type="text" name="form-1-summary" maxlength="50" id="id_form-1-summary" /></td>
    <td><input type="number" name="form-1-time" value="1" id="id_form-1-kosu" /></td>
    <td><input type="text" name="form-1-memo" maxlength="50" id="id_form-1-memo" /></td>

    キャンセル

check解決した方法

0

より良いコードがあるかもしれませんが、
現状以下をページ初期表示時と動的なフォーム追加時に実行させるようにしました。
function update_field(){
var current_count = parseInt($('input#id_form-TOTAL_FORMS').val());
var result = 0;
for(var i = 0; i < current_count; i++){
result = result + parseInt($('#id_form-'+i+'-kosu').val()) ;
$('#total').text(result);
}
}

$(function() {
$('input[type="number"]').on('keyup change', function() {
update_field();
});
});

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

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

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