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

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

ただいまの
回答率

89.10%

javascriptのコードのシンプルな書き方を教えて頂きたいです

解決済

回答 2

投稿 編集

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

parinpurin23

score 17

 前提・実現したいこと

javascriptでinputボックスの値をコピーしたいのですが、値が多くて現状の書き方に不満があります。

どのようにしたらもっとシンプルになるか教えて頂きたいです。

 発生している問題

下記の該当のソースコードのように、目的とする機能AとBがあります。

機能A
ボタンクリックで【入力エリア】の追加と削除を1つずつ行う
(「.data1」「#name1」「#valu1」のセットを連番で増減し、最低で3セットありそれ以下にはならない)

機能B
【入力エリア】を【送信エリア】にコピーする
(最後のカンマはなくし、カンマ連続時は「submit」をdisabledにする)

しかし値1つずつについて書いているために、inputボックスが多い場合への対応が困難となり質問させて頂きました。

 該当のソースコード

サンプルあります。
https://jsfiddle.net/rkc4st3q/3/

<section class="datalist">
  <p>【入力エリア】</p>
  <div class="data1">
    <input id="name1" class="name" type="text">
    <input id="valu1" class="valu" type="number">
  </div>
  <div class="data2">
    <input id="name2" class="name" type="text">
    <input id="valu2" class="valu" type="number">
  </div>
  <div class="data3">
    <input id="name3" class="name" type="text">
    <input id="valu3" class="valu" type="number">
  </div>
  <!-- 同様に「.data4」や「.data5」などが大量にあり、最低で上の3つがある -->
  <button type="button" id="add">add data</button>
  <button type="button" id="remove">remove data</button>
</section>

<section class="outputlist">
  <p>【送信エリア】</p>
  <input id="result_name"><br>
  <input id="result_valu"><br>
  <button type="button">submit</button>
</section>
/*
機能A
ボタンクリックで【入力エリア】の追加と削除を1つずつ行う
(data1,name1,valu1のセットを連番で増減し、最低で3セットありそれ以下にはならない)
*/

$('#add').click(function(){
  if( ($('.data2').css('display')=='none') && ($('.data3').css('display')=='none') ){
      $('.data2').css('display','flex');
  }
  else if( ($('.data2').css('display')=='flex') && ($('.data3').css('display')=='none') ){
      $('.data3').css('display','flex');
  }  
});

$('#remove').click(function(){
  if( ($('.data2').css('display')=='flex') && ($('.data3').css('display')=='flex') ){
      $('.data3').css('display','none');
  }
  else if( ($('.data2').css('display')=='flex') && ($('.data3').css('display')=='none') ){
      $('.data2').css('display','none');
  }  
});


/*
機能B
【入力エリア】を【送信エリア】にコピーする
(最後のカンマはなくし、カンマ連続時は「submit」をdisabledにする)
*/
$(".name").on('keyup',function(){
  var input_name1 = $('#name1').val();
  var input_name2 = $('#name2').val();
  var input_name3 = $('#name3').val();
  var output_names = input_name1+','+input_name2+','+input_name3;
  $('#result_name').val(output_names);
});

$(".valu").on('keyup',function(){ 
  var input_valu1 = $('#valu1').val();
  var input_valu2 = $('#valu2').val();
  var input_valu3 = $('#valu3').val();
  var output_valus = input_valu1+','+input_valu2+','+input_valu3;
  $('#result_valu').val(output_valus); 
});


質問をまとめます。

質問➀:機能Aについて、実際は大量のinputがあるので、このままではif条件が大量になってしまいます。シンプルな書き方を知りたいです。

質問➁:機能Bについて、実際は大量のinputがあるので、このままではvarでの定義が大量になってしまいます。シンプルな書き方を知りたいです。

質問➂:機能Bについて、「値2つにつきカンマを1つ」にして、そしてカンマが連続する場合は「submit」をdisabledにしたいです。
(例えば、[りんご,,なす,,]と[3,,2,,]などを、[りんご,,なす]と[3,,2]のように最後にカンマが一切入らないようにして、さらに[りんご,きゅうり,なす]と[3,4,2]のように修正されるまで、「submit」をdisabledにしたいです。)

 試したこと

上のソースコードのように、1つずつ書いていくところまでしか試せませんでした。

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • m.ts10806

    2018/10/30 05:18

    「inputボックスが多い」だけではイメージがわかないのですが、必ずname+連番の組み合わせなのでしょうか。法則性があるなら要件として追記いただきたいです。①も表示非表示を切り替えしているだけかと思いますが、「多い」ときにどのような法則で切り替えられるのかご提示ください。あとtype="textarea"というのはありません。type="text" もしくはinputタグではなくtextareaタグのどちらかです。(単行なら前者、複数行なら後者です)

    キャンセル

  • m.ts10806

    2018/10/30 05:27

    あと、コード内にコメントとはいえ要件にもあたる今回の質問●●の部分が入っていると要件がくみ取りにくくなります。コードブロック内はなるべく実際のコードのみにしてください。

    キャンセル

  • m.ts10806

    2018/10/30 05:57

    「値2つにつきカンマを1つ」というのは4つ5つと値が増えていった場合にどのような表示になるのでしょうか。結果を例示してください。

    キャンセル

  • parinpurin23

    2018/10/30 11:57

    失礼致しました。法則は仰る通りの連番で、ただし「data」も連番を付けたいです。コードのご指摘もありがとうございます。カンマについて質問を修正させて頂きました。

    キャンセル

回答 2

+2

 前置き

エスパー回答かもしれないのでヒントにして改修してみてください。

 要件(私自身が理解した仕様)

  1. デフォルトで1セット入力エリアがある
  2. 入力エリアの結果を受ける送信エリアがある
  3. 「add data」ボタンで同じ入力エリアセットを入力エリア末尾に追加する
    この場合、「末尾の入力エリアセットの番号+1」を命名する
  4. 「remove data」ボタンで末尾の入力エリアセットを削除する。
    この際、デフォルトの入力エリアセットは残しておくため削除しない(削除ボタン非活性とか)
  5. 何かしら入力された場合、すべての値を結合して「送信エリア」にそれぞれ表示
    ※「値2つにつきカンマを1つ」は値が増えた場合にどう表示するか提示されていないので考慮しない
    ※値が空になっている場合はどうするかは考慮していない(要件次第)

 上記をなんとなく実現したコード

※ざっくり動作検証済みですが、どこかで不具合あるかもしれません。
その場合は、修正してみてください。

<section class="datalist">
  <p>【入力エリア】</p>
  <div class="data">
    <input id="name1" class="name" type="text" placeholder="りんご">
    <input id="valu1" class="valu" type="number" placeholder="2">
  </div>
  <button type="button" id="add">add data</button>
  <button type="button" id="remove" disabled>remove data</button>
</section>

<section class="outputlist">
  <p>【送信エリア】</p>
  <input id="result_name">
  <input id="result_valu">
</section>
$(function(){
    //入力セット追加
    $("#add").on("click",function(){
        var data_count = $(".data").length;

        //蛇足:デフォルト入力セットがないとき
        if(data_count <= 0){
            alert("コピー元データが存在しません");
            return false;
        }
        var next_inputset = $($(".data")[data_count-1]).clone();//最終の要素をコピー
        var next_id = data_count+1;//個数+1をIDとする
        next_inputset.children("input.name").attr("id","name"+next_id);
        next_inputset.children("input.name").val("");
        next_inputset.children("input.valu").attr("id","valu"+next_id);
        next_inputset.children("input.valu").val("");
        $(".data")[data_count-1].after(next_inputset[0]);
        //蛇足:ボタンの状態の切り替え
        //削除ボタンを活性化
        if(next_id == 2){
            $("#remove").prop("disabled",false);
        }
    });
    //入力セット削除
    $("#remove").on("click",function(){
        var data_count = $(".data").length;
        //蛇足:1つもないとき
        if(data_count <= 0){
            alert("削除元データが存在しません");
            return false;
        }
        //蛇足:1つしかないとき
        if(data_count === 1){
            alert("デフォルト入力セットは削除できません");
            return false;
        }
        var last_inputset = $($(".data")[data_count-1]); //最終要素を取得
        last_inputset.remove();
        //蛇足:ボタンの状態の切り替え
        if($(".data").length <= 1){
            $("#remove").prop("disabled",true);
        }

        //蛇足:現在の状態で送信エリアの値を精査
        data_send("name");
        data_send("valu");
    });

    //入力値を結合
    //動的生成要素に対応
    $(document).on("keyup",".name",function(){
        data_send("name");
    });
    $(document).on("keyup",".valu",function(){
        data_send("valu");
    });

    //送信共通メソッド
    function data_send(vname){
        var data_array = [];
        for(var i=0;i<$("."+vname).length;i++){
            data_array.push($($("."+vname)[i]).val());
            //空の場合は考慮していない
        }
        $("#result_"+vname).val(data_array.join(","));
    }
});

 追記

蛇足を沢山入れています。
個人的に考慮しといたほうがいいかなというところです。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/10/30 12:01

    どうもありがとうございます。蛇足のお気遣いまで完璧です。
    あとカンマについてですが、
    ・文字の最後に連続で入ってしまとき
    →その最後のカンマを全て削除。
    ・途中のカンマが連続するとき
    →送信ボタン(急きょ追加)をdisabledにする。
    というイメージでした。

    キャンセル

  • 2018/10/30 12:18

    joinで連結してるので、空のときに追加しないように分岐かければ連続することなくなりますよ

    キャンセル

  • 2018/10/30 13:25

    なるほど。どうもありがとうございます。

    キャンセル

checkベストアンサー

+1

こんにちは。

様々な修正方法や手順があると思いますので、あくまでその一例ということで、以下、回答します。なお、

  • JSだけではなく、HTMLとCSSもリファクタしました。
  • ファイル名を  index.htmlstyle.cssindex.js としました。
  • 動作確認のため、送信エリアの <input> の幅を広げました。

 index.html

<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>Q155041</title>
    <script src="https://code.jquery.com/jquery-3.3.1.min.js"></script>
    <script src="index.js"></script>
    <link rel="stylesheet" href="style.css">
</head>
<body>
    <section class="data-list">
        <p>【入力エリア】</p>
        <div class="data-table">
            <div class="data">
                <input class="name" />
                <input class="valu" type="number" />
            </div>
        </div>
        <button type="button" id="add">add data</button>
        <button type="button" id="remove">remove data</button>
    </section>

    <section class="output-list">
        <p>【送信エリア】</p>
        <input id="result-name" /><br />
        <input id="result-valu" />
    </section>
</body>
</html>

 style.css

p {
    margin: 0px;
}

section {
    border: 1px solid gray;
    margin: 15px 0 0 0;
    padding: 10px;
}

.data-list .data {
    display: flex;
}

.data-list .data input {
    width: 50px;
    margin: 10px 2px;
}

.output-list input {
    width: 95%;
}

 index.js

$(function(){
  /*
  【入力エリア】を【送信エリア】にコピー
  */
  const updateResult = function(clazz) {
    const values = $(`.${clazz}`).toArray().map(e => e.value);
    $(`#result-${clazz}`).val(values.join(','));
  };

  const inputData = function() {
    updateResult($(this).attr('class'));
  };

  $('.data input').on('keyup change', inputData);

  /*
  ボタンクリックで【入力エリア】の追加と削除
  */
  $('#add').click(function(){
    // 一行目をクローン
    const newData = $('.data:first-of-type').clone();

    // input の値を初期化し、イベントハンドラ設定
    $('input', newData)
      .val('')
      .on('keyup change', inputData);

    // data-table に追加
    $('.data-table').append(newData);
  });

  $('#remove').click(function(){
    // データ行が2行以上あれば最後の行を削除し、送信エリアを更新
    if ($('.data').length > 1) {
      $('.data:last-child').remove();
      ['name', 'valu'].forEach(clazz => updateResult(clazz));
    }
  });
});

上記のコードを、以下の2カ所に上げていますので、ご参照ください。

・ jsfiddle: https://jsfiddle.net/jun68ykt/5uqfk8ba/2/

・ GitHub: https://github.com/jun68ykt/q155041
 

GitHubのほうで、initial commit では、ご質問に挙げられているコードをほぼそのまま写しただけなので、git clone するなりして頂き、全コミット を追っていけば、どんな修正をしていったかが分かるかと思います。

以上、参考になれば幸いです。

 追記

ご質問に挙げられているソースコードのコメントに

質問➂:これではカンマが多くなってしまいます。「値2つにつきカンマを1つ」にしたいです。

とありましたが、

「値2つにつきカンマを1つ」にしたい

というのは、<input class="name" /> および<input class="valu" /> の value を、 class が"name"のものと"valu"のものとで分けて、カンマ区切りで並べたい、という意味と解釈して、そのように表示するようなコードを回答しています。
もし、回答に書いたコードが、上記の③含めて、parinpurin23さんがご要望の動作と違うものになっていましたら、コメントからお知らせください。

 追記2

上記の回答に記載したコードから、コメントから頂きました、

parinpurin23 2018/10/30 12:05
ただし、次の2つの場合について
・文字の最後に連続で入ってしまとき
→その最後のカンマを全て削除。
・途中のカンマが連続するとき
→送信ボタン(急きょ追加)をdisabledにする。
というイメージでした。

に対応する修正の一例としては、関数updateResult を以下のようにします。

  const updateResult = function(clazz) {
    // 指定されたクラスの input.value をカンマ区切りにした文字列を作成
    let csv = $(`.${clazz}`).toArray().map(e => e.value).join(',');

    // 末尾にカンマが1個以上あるとき、これを削除
    csv = csv.replace(/,+$/, '');

    // 上記で作成されたカンマ区切りの文字列をvalueに設定し、あわせて連続したカンマがあるかどうかでdisabledを設定
    $(`#result-${clazz}`)
      .val(csv)
      .prop('disabled', /,,/.test(csv));
  };

GitHub のほうも上記の修正のための、以下の2コミットをプッシュしておきました。

・ 末尾にカンマが1個以上あるとき、これを削除
 
・ 連続したカンマを含む場合の対応

後者のコミットでは、 disabled になったことが見て分かるように、 disabled の場合の背景色を #aaa にしました。

 追記3

以下にて、disabled にする対象をsubmitボタンにするのと、先頭のカンマも削除するようにしました。

submitボタンを追加し disabledにする対象を修正

先頭のカンマも削除

git clone しているのでしたら、 pull してご確認ください。

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2018/10/30 15:12

    追記3 にボタンをdisabled にすることと、 先頭のカンマ削除の対応を記載しましたので、ご確認ください。

    キャンセル

  • 2018/10/31 18:32

    いろいろな補足について追記して頂きどうもありがとうございます。お二人のご回答を参考に、無事実装することができました。心から感謝申し上げます。

    キャンセル

  • 2018/10/31 21:20

    > 無事実装することができました。

    とのことで、よかったです👍

    キャンセル

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

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