48253


**「圧縮したHTMLの状態」では正常動作するのですが、HTMLを整形展開すると、下記エラーとなります。**

> Uncaught TypeError: Cannot read property 'childNodes' of undefined
[code]

    hoge.childNodes[1].childNodes[0],
    
[/code]

・恐らく改行が入るからだと思うのですが、改行にも対応するにはどうすれば良いですか？

* * *

### 追記

・コードのどの部分に該当するのか把握できていないので、例えば下記コードだった場合、input要素を取得するとき、改行「あり」「なし」何れにも対応させることはできますか？  
・childNodesでまとめて取得して、ループで何か出来ないのかな、と思ったのですが…

・改行なし

[code]

    <form class="a1"><p class="a2">ファイルを選択</p><p class="a3"><input accept="image/*" class="a4" type="file"></p></form>
    
[/code]

・改行あり

[code]

    <form class="a1">
      <p class="a2">ファイルを選択</p>
      <p class="a3">
        <input accept="image/*" class="a4" type="file">
      </p>
    </form>
    
[/code]

元コードがchildNodeを使用していたのでなるべくそれに沿うようにしようと思ったのですが、例えば、下記のようなコードで取得しても良い？

[code]

    document.getElementsByClassName( "a4" )
    
[/code]


CC BY-SA 4.0
2018-09-08T16:01:03.923
48221
2018-09-10T07:45:27.053
2018-09-10T07:08:36.137
19110
7886
question
javascript dom
hoge.childNodes[1].childNodes[0], を改行にも対応するには？


Mozilla による [`childNodes`
のドキュメント](https://developer.mozilla.org/ja/docs/Web/API/Node/childNodes)には以下のように書かれています。

> `childNodes`
> にはテキストノードやコメントノードなどの非要素ノードを含むすべての子ノードが含まれます。要素のみのコレクションを取得するには、代わりに
> `ParentNode.children` を使用してください。

HTML 側に改行やスペースなどのテキストが入ると、テキストノードが増えるので `childNodes`
のインデックスがずれます。下の例でも、エラーは出ませんが出力が変わります。

[code]

    let x = document.getElementById("foo").childNodes[1].childNodes[0];
    console.log(x);
[/code]

[code]

    <form id="foo"><p class="a2">ファイルを選択</p><p class="a3"><input accept="image/*" class="a4" type="file"></p></form>
[/code]

[code]

    let x = document.getElementById("foo").childNodes[1].childNodes[0];
    console.log(x);
[/code]

[code]

    <form id="foo">
        <p class="a2">ファイルを選択</p>
        <p class="a3">
            <input accept="image/*" class="a4" type="file">
        </p>
    </form>
[/code]

ドキュメントに書かれているとおり、代わりに `children` を使うとテキストノードは無視されます。

[code]

    let x = document.getElementById("foo").children[1].children[0];
    console.log(x);
[/code]

[code]

    <form id="foo">
        <p class="a2">ファイルを選択</p>
        <p class="a3">
            <input accept="image/*" class="a4" type="file">
        </p>
    </form>
[/code]

ただし、 **本当にノードの数を数えて参照する必要があるのか考えてください** 。すべての子ノードに対してイテレートしたいときなどは
`childNodes` や `children` が使いたくなるでしょうが、ただひとつのノードを指定したいために使うのは混乱のもとです。HTML
側が少し変わるだけで参照できなくなりますし、JS 側の可読性も落ちます。目的のノードがひとつしかないと決まっているなら、そのノードに id を振って
`getElementById` するほうが良いでしょう。あるいは場合によっては
`document.getElementById("foo").getElementsByClassName("a4")[0]`
というやり方が便利かもしれません。


CC BY-SA 4.0
2018-09-10T07:39:00.283
48253
2018-09-10T07:39:00.283
19110
48221
answer


状況によって対策は変わります。いくつかありがちな対策を書いてみます。

■ `<input type=file>` に `id` 属性をつけれられる場合

[code]

    document.getElementById('id-of-input-type-file');
    
[/code]

■ `Document`内にクラス`a4`を持つ要素が2つ以上存在しないことが保証されている場合

[code]

    document.getElementsByClassName('a4')[0]
    
[/code]

■ `hoge`内にクラス`a4`を持つ要素が2つ以上存在しないことが保証されている場合

[code]

    hoge.getElementsByClassName('a4')[0]
    
[/code]

■ `document`内に`<input type=file>`が2つ以上存在しないことが保証されている場合

[code]

    document.querySelector('input[type=file]')
    
[/code]

■ `hoge`内に`<input type=file>`が2つ以上存在しないことが保証されている場合

[code]

    hoge.querySelector('input[type=file]')
    
[/code]


CC BY-SA 4.0
2018-09-10T07:45:27.053
48254
2018-09-10T07:45:27.053
3475
48221
answer