🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
JavaScript

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

Q&A

解決済

3回答

527閲覧

JavaScriptでHTMLの<form>要素を取得する際の方法について

H40831

総合スコア975

JavaScript

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

HTML

HTMLとは、ウェブ上の文書を記述・作成するためのマークアップ言語のことです。文章の中に記述することで、文書の論理構造などを設定することができます。ハイパーリンクを設定できるハイパーテキストであり、画像・リスト・表などのデータファイルをリンクする情報に結びつけて情報を整理します。現在あるネットワーク上のほとんどのウェブページはHTMLで作成されています。

0グッド

2クリップ

投稿2019/10/31 10:47

タイトルの通りなんですが、HTMLの<form>をJavaScriptで取得する際、

JavaScript:

1 2document.getElemetById('フォームのID');

↑これで取得する方法がポピュラーかと思うのですが、

JavaScript:

1 2document.forms./*フォームのidまたはname属性*/;

↑これでも取得できるそうです。
また、それを受けて試してみたところ

JavaScript:

1 2document./*フォームのname属性*/; 3document./*フォームのname属性*/./*子要素のidやname属性*/;

↑これでも要素の取得ができるようなんです。
(子要素というのは<input>などです。formに関連しない要素は試してません。)

短く書けるならそのほうが良いとは思うのですが、
一番下の方法は、なんとなく不安な感じもしてます。
これらそれぞれの手法を取る場合の長所・短所など教えていただけないでしょうか?
技術的な長所・短所だけでなく、使用上の所感・ご意見なども参考になるので是非教えて下さい。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

<form name> はform要素群の中で一意である

name属性を持つのは、form要素だけではありません。
同じname属性値を持つ要素が複数存在した場合、document.formNameHTMLCollection を返します。

HTML

1<form name="foo"></form> 2<img name="foo" src="foo.jpg"> 3<script> 4console.log(document.foo); // HTMLCollection(2) [form, img, foo: form] 5</script>

form要素のname属性値が他のname属性値と重複しない場合、document.formName要素ノードを返します。

HTML

1<form name="foo"></form> 2<script> 3console.log(document.foo); // <form name="foo"></form>``` 4</script>

将来的にHTML文書が変更されて、返り値が上記2つの状態に変化することを想定するなら、条件分岐処理でどちらのパターンにも対応できるように書かなければなりません。

JavaScript

1const foo = document.foo; // 要素ノードかHTMLCollectionか不明なノード 2const fooList = foo.length ? foo : [foo]; // HTMLCollection でなければ、配列に格納しておく 3 4for (let i = 0, len = fooList.length; i < len; ++i) { 5 const foo = fooList[i]; 6 7 if (foo.tagName === 'FORM') { 8 console.log(foo); // <form name="foo"></form> 9 break; 10 } 11}

既存の名前空間を破壊する

document.body のように予め用意されたプロパティであっても、容赦なく破壊します。

HTML

1<form name="body"></form> 2<script> 3console.log(document.body); // <form name="body"></form> 4 5/** 6 * body要素ノードにform要素ノード挿入を試みる 7 */ 8document.body.appendChild(document.createElement('form')); 9console.log(document.body); // <form name="body"><form></form></form> 10</script>

本事象を回避する為に、組み込みのプロパティ名がドット記法で参照可能な名前に限定されている事に着目し、ドット記法では表せない名前にする方法があります。
例えば、- はその一つであり、Selectors APIとも相性が良いので、お勧めです。

document.forms

form.formname は下記コードの簡易版です。

JavaScript

1document.forms['formName']

form要素ノードに限定されている為、<img name> 等の他要素のname属性値と衝突する事はありません。
document.formsHTMLCollection を返すAPIで現在でも実用できます。

ただし、HTMLCollection は id または name 属性値を検索するので、id属性値とは衝突します。
DOM Standard仕様上は「コレクションの中で初めに出現する要素」を参照します。

Return the first element in the collection for which at least one of the following is true:

  • it has an ID which is key;
  • it is in the HTML namespace and has a name attribute whose value is key;

が、「Google Chrome 78.0.3904.87」は順序に関わらず、id属性値を優先しました。
name属性値と衝突しないように気をつけた方が良さそうです。

HTML

1<form name="foo"></form> 2<form id="foo"></form> 3<script> 4console.log(document.forms['foo']); // <form id="foo"></form> 5</script>

古いAPIが使えないわけではない

querySelector がある今現在でも getElementById は現役です。
「古い」は「使わない理由」になりませんが、具体的な問題点があるなら、それは理由になります。
各々の性質を見極めて、状況判断で新旧に囚われずに選択する方がコードの幅が広がって良いと思います。

Re: H40831 さん

投稿2019/11/01 13:00

編集2019/11/02 09:11
think49

総合スコア18189

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

H40831

2019/11/02 15:57

実用上の具体的な注意点を教えていただきありがとうございます! 拝見させていただいたところ、古い方の書き方だと挙動が不安定だということがしっかり理解できました! もしこの古い書き方をリファクタリングする機会があった際には、 またこちらの回答を参考にさせていただく事になるかとおもいます! ご丁寧な解説、どうもありがとうございました!
guest

0

ベストアンサー

はじめに

コメントを受けて改訂した内容となります(回答の文中で斜体となる編集箇所です)。


※ご意見でもいいとのことでしたので

短所しかないですよ

ドットで区切るプロパティPATH(造語:某Nodeモジュール内で関数の引数名に記述されていた propertyPath より)の記法は、DOMの概念がなかった頃の名残です。
最初はDOMなんて無かったですから。

プロパティPATHの時代

まだNetscapeNavigatorが息づいていた頃。JavaScriptは完全に趣味で「JavaScriptポケットリファレンスの改定2版(1999年5月)」で独習していました。その頃の記法です。
当時はJavaScriptは危険だと言われていて、ウェブサイトもTABLE要素で無理やりデザインし、GIFアニメで表現する程度だったんです(あの Dreamweaver でさえもTABLEデザイン用に特化されていました)。

DOMの時代

それから時を経てDOMの整備が進み、TABLEデザインとHTML+CSSの混在、HTML+CSS2、XHTML+CSS2と変わり、今のHTML5+CSS3に至ってます。
CSS2になってもしばらくは、JavaScriptの危険性(ブラウザ実装による)を謳う人も多かったんですよ。

閑話休題

プロパティPATHの記法に話を戻すと、短所しかないです。というか、使いどころが減りました。
HTML上でFORM要素__以下に含まれる入力フィールドの要素__ のname属性が変わるとJavaScriptでも大量の書き換えが発生します。ブラケットで書く場合には変数を使えますがコードが長いことに変わりなかった。

今もコードを書くのは「人」ですよね。
なので「書き換え事案の発生のたびに typo を誘発する。」ことに。
幸いにもJavaScriptが主流になるのはDOMが整備されてからでした。

DOMが整備された頃、 ビルトインオブジェクトを拡張して多機能化(今では禁忌の手法)する Ajaxライブラリ(Prototype.js) や DOM操作に主眼をおいたAjaxライブラリ(jQuery)が登場したのです。

こういう歴史を知っていると、普通にDOMを使っている今は「あるべき姿に改善されていった」だけでしかない。ポピュラーというのも違うんですよね。モダンという言葉が似合っていると思います。

querySelectorAll("input[type=text]") で複数のテキストフィールドを取得できる素晴らしさを、昔の自分に教えるとどうなるだろうと感じます。


コメントへの回答:(追記)

「書き換え事案の発生のたびに typo を誘発するとは?」
要はヒューマンエラーの削減に関することです。

  • プロパティPATHは必ず フォームフィールド部分で javascript の編集がつきまとっていました
  • DOMはそうでもなくなった(AjaxでPOSTする事例をコードで示してみます)。

javascript

1// コメントを受け、関数化したものに変更しています 2function getFormInputs( elem ) { 3 var postJson = {} 4 , form, fields, field, name, value 5 ; 6 7 if( "string" === typeof elem ) { 8 // DOM のセレクタを与えた場合 9 form = document.querySelector( elem ); 10 } 11 else if( elem instanceof HTMLFormElement ){ 12 // getElementsById() で得られたHTMLFormElement や 13 // window.forms[`${formName}`] を与えた場合 14 form = elem; 15 } 16 // 例外処理は省略 17 18 fields = form.querySelectorAll("input") 19 for(var i=0; i<fields.length; ++i ){ 20 field = fields[i]; 21 name = field.getAttribute("name") || field.id; 22 value = field.value || ''; 23 24 postJson[name] = value; 25 } 26 return postJson; 27} 28console.log( JSON.stringify( getFormInputs( {HTMLFormElement|selector} ) ) ); // AjaxでPOSTするデータ

このように、HTMLの変化があっても使える 使い回しの効く コードになります。
人為的なコード改変が減る=ヒューマンエラーも減ると言えますよね。

ヒューマンエラーは、人が集中を欠くと発生しちゃいます。些細な悩み事でもです。
ヒューマンエラーの発生率を下げるにはコード自体の改変量を減らすなどの工夫が不可欠ですが、DOMならそれができます。

最後に

最初に回答した時点では、言葉足らずのために多くが曖昧な表現となっていました。
そのような稚拙な文章をお読みになられた方々にはこの場を借りて謝罪いたします。

貴重なお時間を割いてしまい、申し訳ありません。

また、再度の推敲を促してくださった、質問者 (H40831 さん)、他のコメントを投げてくださった、think49さん、yamabejpさんには、併せて感謝申し上げます。

編集事由につきましては、コメント欄でのやりとりをご覧くださいませ。

AkitoshiManabe

投稿2019/10/31 13:41

編集2019/11/01 22:35
AkitoshiManabe

総合スコア5434

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

H40831

2019/10/31 16:48 編集

まさしくこういうご意見が欲しかったところです。ありがとうございます。 今勉強を始めてる初心者にとっては、どの手法が古く危ういもので、どの手法が新しく安全なものであるかを知ることは、人に聞かないとなかなか難しいのです。。。 2つめ、3つめの記法が古く非推奨なものであるというだけで十分使わない理由にはなるのですが、 一点だけ理解しきれてない部分があるので、 ベストアンサーにさせていただく前に教えていただけたら幸いです… 「書き換え事案の発生のたびに typo を誘発する。」というのはどういう事でしょうか? HTMLの書き換えがあったときにJavaScriptも書き換えないといけないという意味であれば、getElementByIdで書いてたとしても、id変えた際には変数を使ってない場合は結局全箇所書き換えなければいけないですよね?
AkitoshiManabe

2019/10/31 21:23

コード改変=ヒューマンエラー発生率の増加という意味です。回答欄に追記しますね。
H40831

2019/11/01 01:42

追記までしていただき、ありがとうございます! 恐縮ですが知識不足のようでいまいち完全に掴みきれてないのですが、 当初の疑問は解消されたのでベストアンサーとさせていただきます。
AkitoshiManabe

2019/11/01 01:45

>HTMLの書き換えがあったときに…(略) 10の手間(プロパティPATH)を1の手間(DOM)にすると効率は上がります。だから関数化して id 指定できれば良い形にしたり、発展したライブラリがある。10の手間をゼロにする必要があるのなら、それはAIにプログラムを書かせることを意味した未来の話です。
H40831

2019/11/01 05:47

document.getElementById(form) と、 document.form だったら後者の方が手数は少ないと思ったのですが、 自分が試してみた範囲が、 要素を代入してみて、コンソールでタグを表示できるかどうかを見てみただけなのでよくわかってないのかもしれません! プロパティパスの書き方だと、希望の処理をするためにもっと色々書き込まなければいけないとかそういうことでしょうか? プロパティパス?という呼び方自体この質問ではじめて耳にしたので、それについての仕様などは(検索ワードも分からなかったので)まだ調べてません。
AkitoshiManabe

2019/11/01 06:28

1回こっっきりの使い捨てのコードなら H40831 さんの手数論は正しいです。DOMの場合、最初は手数がいるのだけど、使い回しが効くんです。項目数もバラバラな「お問い合わせフォーム」にも対応しなければなりませんから、2回目以降の手数が激減するんです。DOMの実装を関数化して引数にFORM要素を与える必要があるとき、document.form を渡すのも当然有りです。 最後に、プロパティPATHについては、はごめんなさい。「用語じゃない」です。Nodeモジュールのどれかにあった関数の引数にかかれていた propertyPath をカタカナで書いたんですよ。javascriptオブジェクトの ドット区切りの階層をたどる記述として直感的なワードだったので。 これは誤解させちゃいましたね。申し訳ありませんm(_ _)m
AkitoshiManabe

2019/11/01 06:46

> プロパティパスの書き方だと、希望の処理をするためにもっと色々書き込まなければいけないとかそういうことでしょうか? フォーム要素はともかく、その子孫に置かれるINPUTなどのフィールドを成す要素が厄介ですね。お問い合わせフォームの各フィールドのname属性を「日本語で」とか要望があると震え上がります。回答欄の追記に示したとおり、DOMで自動化するわけです。 大事なことなので、もう一度。「プロパティPATH」は造語ですよ。
H40831

2019/11/01 09:08

造語なんですね!わかりました! 手法の新旧がわからない+手法の呼び名も分からない(orそもそも呼び名は特にない)というパターンで、 学習がどん詰まりになる事は初心者あるあるだと思います…。 ご丁寧に教えていただいてありがとうございました! とても助かりました^^
think49

2019/11/01 12:08

終わった話題を蒸し返すようですが、 > HTML上でFORM要素のname属性が変わるとJavaScriptでも大量の書き換えが発生します。ブラケットで書く場合には変数を使えますがコードが長いことに変わりなかった。 getElementByIdもid属性値が変わると、JavaScriptコードの書き換えが発生します。 なので、これは短所になっていないように受け取れるのですが、私の捉え方が悪いのでしょうか。 少なくとも、三人の支持者がいるようなので、ちょっと自信がなくなってきました。 結論には同意しますが、私は別の理由を想定していました。
AkitoshiManabe

2019/11/01 21:29

think49 さん、考え方は間違ってないですよ。問題なのはむしろ「私の回答欄での記述」です。曖昧さが多く含まれていて、読まれた方の受け取り方次第で混乱をもたらしています(質問者の H40831 さんとのコメントでの遣り取りでも気付かされました)。再度推敲し、更新させていただくつもりです。まずは、貴重なお時間を割いて読んでくださったことに感謝いたします。m(_ _)m
think49

2019/11/03 04:14

@AkitoshiManabe さん 追記されたコードを拝見しましたが、実引数でform要素ノードを渡す設計にすれば、どのやり方でも「コード書き換え箇所を最小限」に出来るように思います。 https://plnkr.co/edit/J8UJevhm8RX0d3Zwud03?p=preview
AkitoshiManabe

2019/11/03 04:29

コメントありがとうございます。「new FormData(form)を介するのが一番早い」は盲点でした。 因みにですが、現役ではなくなって「素人」に戻っておりますので、現役は豪腕だなと感じております。 「頓珍漢」なことを言っていたら、容赦なくご批判くださいね。
think49

2019/11/03 04:56 編集

@AkitoshiManabe さん FormDataは論点ではないのですが…。 私の意図は document.forms でも document.querySelector でも「HTMLの変化があっても使い回しの効くコード」になる、という事です。 そうなると、これは「document.forms の短所」ではなくなってしまいます。 --- 質問者の意に沿うよう、JavaScriptに限定して回答していましたが、実運用上はHTMLのマークアップポリシーの影響が大きいと考えています。 A. <form id> だけを使う B. <form name> だけを使う C. <form id name> を併用する A. は、どの書き方でもあってもコード書き換え対象は変わりません。 B. は、<img name> 等、他要素で同値のname属性値がなければ、どの書き方でもあってもコード書き換え対象は変わりません。 C. は、id,name属性値が同値である限り、どの書き方でもあってもコード書き換え対象は変わりません。 制限が最小なのは A. で「id属性/name属性のどちらを採用するか」が争点です。 URLハッシュ値として使えるid属性値に優位性がある(ユーザビリティが高い)のは間違いなく、最終的には名前の運用管理の都合次第という事になります。
guest

0

レガシーな書き方だと

javascript

1<script> 2window.addEventListener('DOMContentLoaded', ()=>{ 3 console.log(document.forms["f1"].elements["n13"].id); 4 console.log(document.forms[1].elements[1].id); 5 console.log(document.f3.n31.id); 6}); 7</script> 8<form name="f1"> 9<input name="n11" id="i11"> 10<input name="n12" id="i12"> 11<input name="n13" id="i13"> 12</form> 13<form name="f2"> 14<input name="n21" id="i21"> 15<input name="n22" id="i22"> 16<input name="n23" id="i23"> 17</form> 18<form name="f3"> 19<input name="n31" id="i31"> 20<input name="n32" id="i32"> 21<input name="n33" id="i33"> 22</form>

昔はなんでもnameでした。
nameが原則uniqueである必要がないことから色々工夫され
getElementsByName的な処理もされましたが、
現在はquerySelectorでタグ名、id、クラスなどで
きちんと系統だったアクセスするのが主流です。

投稿2019/11/01 01:54

yambejp

総合スコア116688

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

H40831

2019/11/01 09:12

ありがとうございます! どんどん技術を深堀りしていきたい段階ですので、 今後もこういう非推奨の技術を目にする機会は多くなるとおもいます。 時系列の都合で残っているような非推奨のやり方に注意しながら情報収集したいとおもいます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問