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

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

ただいまの
回答率

90.75%

  • PHP

    19204questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • JavaScript

    15310questions

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

  • CSS

    5342questions

    CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

  • HTML5

    3729questions

    HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。

入力項目の多い画面の設計について

解決済

回答 2

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 626

annderber

score 66

お世話になります。

現在作成している入力フォームで、かなりネストの深いものがあります。具体的に言うと、一対多の関係にあるフォーム群が2つあり、これがツリー構造のように下に伸びています。

またこのフォームはJavaScriptで動的に増やせるようにしています。
ここで問題なのがname属性のつけ方です。動的に増えるフォーム内にチェックボタンラジオボタンが複数あるため、フォームを追加する際にJavaScriptでname属性の[]内の値をインクリメントしています。
これが非常に厄介で例えばname="hoge[0][huga][1][]のようなフォームが沢山あります。

このように一対多の関係にあるフォームが複数ある場合の画面をどう作成したらいいでしょうか。なるべく1つの画面に収まるようにしたいです。

ここでの1つの画面とは画面遷移せず、またメインの入力画面にすぐ戻れるようになっている状態という意味でとらえていただければと思います。なので、フォームを分割してモーダルなどで表示したりタブで分けたりするのもいいかなと思います。

改善したい点は2つで。
・長いname属性
・画面の表示領域にフォームが詰まりすぎてデザインがよろしくない
になります。

画面レイアウトイメージは以下のような感じです。
イメージ説明

質問が分かりづらくてすいません。
よろしくお願いします。

追記:
javascript側でのフォーム追加処理はこんな感じです。※jquery使ってます

$load_content.on("click",".js_add_form_child", function() {
        //一番最後のフォームグループ取得
        var $form_group = $(this).parents('.panel-body').find(".form_group").last();
     //フォームグループの要素数からname属性インクリメント用の値取得
        var new_form_cnt = $(this).parents('.panel-body').find(".form_group").length;

       //既存のフォームのname属性から新しいフォームの用のname属性文字列を生成
       var new_form1_name = $form_group.find(".js_form1").attr("name").replace(/(table_name\[\d+\]\[form1\]\[)\d+(\])/g, "$1"+new_form_cnt+"$2");
       var new_form2_name = $form_group.find(".js_form2").attr("name").replace(/(table_name\[\d+\]\[form2\]\[)\d+(\])/g, "$1"+new_form_cnt+"$2");
       var new_form3_name = $form_group.find(".js_form3").attr("name").replace(/(table_name\[\d+\]\[form3\]\[)\d+(\])/g, "$1"+new_form_cnt+"$2");

        //既存のフォームをクローンしてフォーム群の末尾に追加
        $form_group.clone(false)
        .find(".js_form1").attr('name', new_form1_name).end()
        .find(".js_form2").attr('name', new_form2_name).end()
        .find(".js_form3").attr('name', new_form3_name).end()
        .insertAfter($form_group);
    });

new_formのname属性生成処理は正規表現の使い方で1つにまとめられると思ってます

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

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

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

  • asahina1979

    2017/12/15 10:56

    繰り返し項目は同じ仕様ならまとめることは可能ですが、提出先に問合せしましょう。(上限まで書くか)

    キャンセル

  • mts10806

    2017/12/15 11:19 編集

    「1つの画面」という表現には色々と含まれると思います。ブラウザは横にも縦にもスクロール可能なので、スクロールすれば「1つの画面」は無限の幅を持ちます。「最大化した状態で全て見える」とするのであれば、「JavaScriptで動的に増やせる」時点で制限は不可能です。「複数ページに渡らず」という捉え方もできますので、(ブラウザを縦横小さく畳むこともできますし)「1つの画面」というものの定義をしっかり提示された方がより欲しい情報・回答が得られるかと思います。

    キャンセル

  • annderber

    2017/12/15 11:38

    コメントありがとうございます。再度修正しました。

    キャンセル

回答 2

checkベストアンサー

+2

 多次元配列

これが非常に厄介で例えばname="hoge[0][huga][1][]のようなフォームが沢山あります。

逆に質問させて頂きたいのですが、なぜそんなに複雑な名前が必要なのでしょうか。
JavaScriptで動的に要素を増やす場合に配列構造が必要になるのは分かります。
が、formはネストできず、formと各要素の関係性も一対多なので、要素の名前も一次元配にしかなり得ないと考えています。
フォーム群1に対して、フォーム群1-1,1-2が増えて行くのなら、

<fieldset>
  <legend>フォーム群1-1</legend>
  <input name="foo-1[0]">
  <input name="foo-1[1]">
</fieldset>

<fieldset>
  <legend>フォーム群1-2</legend>
  <input name="foo-2[0]">
  <input name="foo-2[1]">
</fieldset>

`

サーバサイドで多次元配列を受け取れるなら、

<fieldset>
  <legend>フォーム群1-1</legend>
  <input name="foo[0][0]">
  <input name="foo[0][1]">
</fieldset>

<fieldset>
  <legend>フォーム群1-2</legend>
  <input name="foo[1][0]">
  <input name="foo[1][1]">
</fieldset>

`

index値が多少増える程度で名前はそこまで長くはならないように思います。

 JavaScriptコード

javascript側でのフォーム追加処理はこんな感じです。※jquery使ってます

HTMLが見えないのでどういう理屈でそのコードに至ったのかまで読み取れませんでしたが、私なら次のように書きます。

<form>
  <input class="insert-fieldset" type="button" value="追加">
  <fieldset>
    <legend>フォーム群1</legend>
    <p><input type="text" name="table[0][text][0]"></p>
    <p><input type="text" name="table[0][text][1]"></p>

    <input class="insert-fieldset" type="button" value="追加">

    <fieldset>
      <legend>フォーム群1-1</legend>
      <p><input type="text" name="table[0][group][0][0]"></p>
      <p><input type="text" name="table[0][group][0][1]"></p>
    </fieldset>

    <fieldset>
      <legend>フォーム群1-2</legend>
      <p><input type="text" name="table[0][group][1][0]"></p>
      <p><input type="text" name="table[0][group][1][1]"></p>
    </fieldset>
  </fieldset>

  <fieldset>
    <legend>フォーム群2</legend>
    <p><input type="text" name="table[1][text][0]"></p>
    <p><input type="text" name="table[1][text][1]"></p>

    <input class="insert-fieldset" type="button" value="追加">

    <fieldset>
      <legend>フォーム群2-1</legend>
      <p><input type="text" name="table[1][group][0][0]"></p>
      <p><input type="text" name="table[1][group][0][1]"></p>
    </fieldset>

    <fieldset>
      <legend>フォーム群2-2</legend>
      <p><input type="text" name="table[1][group][1][0]"></p>
      <p><input type="text" name="table[1][group][1][1]"></p>
    </fieldset>
  </fieldset>
</form>

<script>
'use strict';
jQuery('form').on('click', '.insert-fieldset', function handleClick (event) {
  var input = jQuery(event.target),
      nestLevel = input.parents('fieldset').length + 1,
      lastFieldset = input.nextAll('fieldset:last()'),
      fieldset = lastFieldset.clone(true),
      legend = fieldset.find('legend'),
      textNode = legend[0].firstChild,
      beforeTopLevelCaption = textNode.data,
      match = /^(\D*(?:\d+\D*)*)(\d+)$/.exec(beforeTopLevelCaption),
      afterTopLevelCaption = match[1] + ++match[2];

  textNode.data = afterTopLevelCaption;

  for (var i = 1, len = legend.length, text, index; i < len; ++i) {
    textNode = legend[i].firstChild;
    text = textNode.data;
    index = text.indexOf(beforeTopLevelCaption);

    if (index !== -1) {
      textNode.data = text.slice(0, index) + afterTopLevelCaption + text.slice(index + afterTopLevelCaption.length);
    }
  }

  for (var i = 0, inputList = fieldset.find('input[type="text"]'), len = inputList.length, input, name, reg = /\[\d+(?=\])/g, result, j, index, bracket; i < len; ++i) {
    input = inputList[i];
    name = input.name;
    j = 0;
    reg.lastIndex = 0;

    while (result = reg.exec(name), ++j < nestLevel);

    index = result.index;
    bracket = result[0];
    input.name = name.slice(0, index) + '[' + (+bracket.slice(1) + 1) + ']' + name.slice(index + bracket.length + 1);
  }

  lastFieldset.after(fieldset);
});
</script>

Re: annderberさん

投稿

編集

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/12/15 18:10

    コメントありがとうございます。
    私の場合サーバーサイドで処理を行いやすくするためにname属性が長くなりがちです。

    私的命名規則では以下になります。

    name="table_name[form_gruop1_index][form_name][form_group2_index]"

    checkboxの場合は複数の値を受け取ることを想定し、末尾に[]を増やします。

    name="table_name[form_gruop1_index][form_name][form_group2_index][]"

    先頭にテーブル名を付けるのはサーバー側でテーブル毎の値をまとめて取得できるようにするためです。
    ここは本来必要ないので省略してもいいですね。

    think49さんの回答を見て、以下の方がいい気がしてきました。
     name="table_name[form_gruop1_index][form_group2_index]form_name"

    キャンセル

  • 2017/12/15 23:13

    フォーム1、フォーム2を含めて、「一つの多次元配列」にまとめるのが目的でしょうか。
    その場合は name="table[0][name][0][0]" になるのは致し方ないように思います。
    多次元配列部分を短くしたいのなら、多次元配列を使う事を諦めるしかありませんが、管理性を求めて多次元配列を使っていると思われる為、名前を短くするために多次元配列を廃止するのは、本末転倒だと私は思います。

    キャンセル

  • 2017/12/16 12:16

    コメントありがとうございます。
    まさに1つの多次元配列にまとめるのが目的です。
    やはりあきらめるしかないでしょうか。また面倒なのが、html側のname属性を変更するとjavascript側でname属性の値をインクリメントする処理部分も修正する必要があるというところです。正規表現をうまく使えば回避できそうですが。

    キャンセル

  • 2017/12/16 12:47

    > javascript側でname属性の値をインクリメントする処理部分も修正する必要がある
    末尾のインデックス値をインクリメントするなら、ご想像の通り、正規表現で対応できますね。
    最も、サーバサイドにPHPを使用しているのなら、name="foo[]" で良い気もします(インデックス値はPHPが補完します)。

    一元管理出来るのなら、基本的にはコード量が減ります。
    が、annderber さんはむしろ負担に感じているようなので、何かしらコードの書き方に問題がありそうです。
    例えば、JavaScriptでノードを動的に追加する関数は一つだけ定義すれば良いのですが、そうなっているでしょうか。
    [追加] ボタンのdata-targer属性に「対象のノードを特定するセレクタ文字列を指定する」や「[追加] ボタンの兄弟要素を元にノードを挿入する」という方法が考えられます。

    キャンセル

  • 2017/12/16 14:06

    コメントありがとうございます。
    javasciprt側でのフォーム生成処理のコードを質問項目に追加しました。
    そこまで悪い処理でないと思っているのですが、どうでしょう。

    また動的にフォームを追加する場合だとまず初期表示でphp側でforeachなどでname属性にindexを渡してやって、その後の動的追加処理はjavascirptでやるという処理が2つに分けられているという感じがあまり好きでないですね。面倒くさがりすぎなのかもしれないですが。

    キャンセル

  • 2017/12/18 14:54

    > javasciprt側でのフォーム生成処理のコードを質問項目に追加しました。
    親記事に追記しました。

    キャンセル

  • 2017/12/20 21:52

    コメントありがとうございます。
    返信おくれてすみません。

    わざわざコードのサンプルまで書いていただけるとは!
    現在コードを読んでいますが、私にとっては結構複雑なコードで読むのに手間取っていますw
    少しずつ読み解いて勉強させていただきます。

    キャンセル

+2

なるべく1つの画面に収まるようにしたいです。

この要望がmustかどうかではないでしょうか。

mustであるなら、ある程度処理が複雑になることはあきらめるしかないでしょう。

そうでなく手順の分割が可能であるなら、
1)基本情報の入力
2)フォーム群1の入力
3)フォーム群2の入力
・・・
というように画面を分けた方がよいと思います。

画面遷移なしに1画面で完結できる利点は、全ての入力内容を確認しながら作業できることと、データのカタチとして完全な状態でDBに格納できる点などがあげられます。
その点、手順を分割した場合は一度不完全な状態で保存しなければなりません。

誰かがそれを見て何らかの不都合が生じるのであれば、不完全な状態の保存をしてはいけない=手順分割できない、ということになります。

逆の見方をすれば、手順が分割されている方が部分的な保存が可能であり、誤った操作をしても今作業している画面の情報が失われるだけで、全てが消えてしまうことはありません。

画面遷移なしの場合は、入力が完全に終わるまで席を離れられないうえ、誤操作などで「せっかく入力したものが全て水の泡・・・」みたいなことも想定されます。

私としては「入力画面」の滞在時間はできるかぎり短くすべきと思います。

ただし、例えばその入力画面が「手動編集用」であって別ルートでデータ入力される仕組みがあるのであれば、入力項目の多い編集画面もアリだと思います。

あまり具体的な解決方法は提示できませんでしたが、以上ご参考まで。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2017/12/15 18:13

    コメントありがとうございます。
    できれば私も画面分割をしたいと考えていますが、
    一覧性が高い方が好まれる場合もあるようです。

    最近だとajaxでフォーム毎にデータを更新するところも多い気がします。

    キャンセル

  • 2017/12/15 23:13 編集

    誤コメントの為、削除

    キャンセル

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

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

関連した質問

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

  • PHP

    19204questions

    PHPは、Webサイト構築に特化して開発されたプログラミング言語です。大きな特徴のひとつは、HTMLに直接プログラムを埋め込むことができるという点です。PHPを用いることで、HTMLを動的コンテンツとして出力できます。HTMLがそのままブラウザに表示されるのに対し、PHPプログラムはサーバ側で実行された結果がブラウザに表示されるため、PHPスクリプトは「サーバサイドスクリプト」と呼ばれています。

  • JavaScript

    15310questions

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

  • CSS

    5342questions

    CSSはXMLやHTMLで表現した色・レイアウト・フォントなどの要素を指示する仕様の1つです。

  • HTML5

    3729questions

    HTML5 (Hyper Text Markup Language、バージョン 5)は、マークアップ言語であるHTMLの第5版です。