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

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

ただいまの
回答率

90.62%

  • JavaScript

    15883questions

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

javascriptとbodyの順を逆にしたら動かなくなった。

解決済

回答 6

投稿 編集

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

R.lawliet

score 44

作成したプルダウンメニューについての評価を頂いた際に、
ヘッダの中にscriptを書いたほうが良いと言われたので移植してみたのですが、
なぜか動かなくなりました。

とても慎重に行ったのでコピペ漏れがあるとかは無いと思います。
out.printを用いて上から見ていったところ、★の箇所で止まっている様でした。

これはコピペ移植する前の状態の時に、
サンプルソースから引っ張ってきた時からくっついていたもので、
正直存在意義が分からなかったので消そうとしたらエラーが発生するので
見てみぬフリをしてやり過ごそうとした所でした。

質問の要点は2つです。
なぜscriptの位置を動かしただけでエラーが発生したのか。

このエラーが出ている★箇所は本来どういう目的で作用していて、
どう対応すれば本来の動きに戻るか、です。

どうかよろしくお願いします。

↓動いていた時のコード
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
 <head>
   <title>情報入力画面</title>
  <meta http-equiv="Content-Script-Type" content="text/javascript">
 </head>
 <body bgcolor = "#bce2e8">

  <form name="registration" method="post" action="" onSubmit="return check()">
   <hr width="100%" size="4">
   <font size="7" color="#0000ff"><div align=center>情報入力画面</div></font>
   <hr width="100%" size="4">
   <table width="400px" height="60%" border="0" align="center" valign ="middle">

    <tbody>
     <tr>
      <td valign ="middle">
       <div>生年月日<select name="selectYear" id="selectYear" onchange="setSelectMonth()">
       </select>年<select name="selectMonth" id="selectMonth" onchange="setSelectDate()">
       </select>月<select name="selectDate" id="selectDate">
       </select>日</div>
       <div align="center"><input type="submit" value="登録"</input></div>
      </td>
     </tr>
    </tbody>
   </table>
   <hr width="100%" size="4">
  </form>
<script type="text/javascript">//属性
<!--

/*=========[ 生年月日 : プルダウン選択 ]=========*/

var Now = new Date();
var NowYear = Now.getFullYear();

/*[ オプションを更新(年) ]*/

function setSelectYear(){
    for(var y=NowYear-40; y<NowYear-17; y++){

        //selectボックスIDからElementの取得
        var selectElement = document.getElementById("selectYear");

        //<option>要素を追加
        var option = document.createElement("option");
        //optionのvalue属性を設定
        option.value = y;
        //リストに表示するテキストの設定
        option.text = y;
        //セレクトボックスにオプションを追加
        selectElement.appendChild(option);
    }
    setSelectMonth();

}
setSelectYear();//★★★存在意義がわからなかった★★★

/*[ オプションを更新(月) ]*/
function setSelectMonth(){
var selectElement = document.getElementById("selectMonth");
var child;
//セレクトボックスの子要素を取得しつつループ
while(child = selectElement.firstChild){ 
    //セレクトボックスから子要素を削除
    selectElement.removeChild(child); 
}

for(var m=1; m<=12; m++){
    var option = document.createElement("option");
    option.value = m;
    option.text = m;

    selectElement.appendChild(option);

    }
    setSelectDate();
}

/*[ オプションを更新(日) ]*/

function setSelectDate(){
    //選択された年を取得
    var Year =
    document.registration.selectYear.options[
    document.registration.selectYear.selectedIndex].value;
    //選択された月を取得
    var Month =
    document.registration.selectMonth.options[
    document.registration.selectMonth.selectedIndex].value;

    //うるう年に対応出来る月の最終日を取得
    var lastDate = new Date(Year,Month,0).getDate();

    var selectElement = document.getElementById("selectDate");
    var child;
    while(child = selectElement.firstChild){
    selectElement.removeChild(child);
    }

    for(var d=1; d<=lastDate; d++){
        var option = document.createElement("option");
        option.value = d;
        option.text = d;
        selectElement.appendChild(option);
    }
}
// -->
</script>
</body>

</html>

↓移植して動かなくなったコード
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> 
<html>
 <head>
   <title>情報入力画面</title>
  <meta http-equiv="Content-Script-Type" content="text/javascript">
  <script type="text/javascript">//属性
<!--
/*=========[ 生年月日 : プルダウン選択 ]=========*/

var Now = new Date();
var NowYear = Now.getFullYear();

/*[ オプションを更新(年) ]*/
setSelectYear();
function setSelectYear(){
    for(var y = NowYear-40; y <= NowYear-17; y++){

        //selectボックスIDからElementの取得
        var selectElement = document.getElementById("selectYear");

        //<option>要素を追加
        var option = document.createElement("option");
        //optionのvalue属性を設定
        option.value = y;
        //リストに表示するテキストの設定
        option.text = y;
        //セレクトボックスにオプションを追加
        selectElement.appendChild(option);
    }
    setSelectMonth();

}
setSelectYear();//★★★ここで止まる★★★

/*[ オプションを更新(月) ]*/
function setSelectMonth(){
    var selectElement = document.getElementById("selectMonth");
    var child;

//セレクトボックスの子要素を取得しつつループ
while(child = selectElement.firstChild){ 
    //セレクトボックスから子要素を削除
    selectElement.removeChild(child); 
}

for(var m = 1; m <= 12; m++){
    var option = document.createElement("option");
    option.value = m;
    option.text = m;

    selectElement.appendChild(option);

    }
    setSelectDate();
}

/*[ オプションを更新(日) ]*/

function setSelectDate(){
    //選択された年を取得
    var Year =
    document.registration.selectYear.options[
    document.registration.selectYear.selectedIndex].value;
    //選択された月を取得
    var Month =
    document.registration.selectMonth.options[
    document.registration.selectMonth.selectedIndex].value;

    //うるう年に対応出来る月の最終日を取得
    var lastDate = new Date(Year,Month,0).getDate();

    var selectElement = document.getElementById("selectDate");
    var child;
    while(child = selectElement.firstChild){
        selectElement.removeChild(child);
    }
    for(var d = 1; d <= lastDate; d++){
        var option = document.createElement("option");
        option.value = d;
        option.text = d;
        selectElement.appendChild(option);
    }
}
// -->
  </script>
 </head>
 <body bgcolor = "#bce2e8">

  <form name="registration" method="post" action="" onSubmit="return check()">
   <hr width="100%" size="4">
   <font size="7" color="#0000ff"><div align=center>情報入力画面</div></font>
   <hr width="100%" size="4">
   <table width="400px" height="60%" border="0" align="center" valign ="middle">

    <tbody>
     <tr>
      <td valign ="middle">
       

       <div>生年月日<select name="selectYear" id="selectYear" onchange="setSelectMonth()">
       </select>年<select name="selectMonth" id="selectMonth" onchange="setSelectDate()">
       </select>月<select name="selectDate" id="selectDate">
       </select>日</div>
       <div align="center"><input type="submit" value="登録"</input></div>
      </td>
     </tr>
    </tbody>
   </table>   
 </form>
</body>

</html>

修正を行いました。
ここで止まるっていう箇所の内容がselectMonthになっていましたが、
selectYearの移し間違いです。

質問している問題点とは別の単なる質問するときに間違えたミスです。
回答者様が困らない様以後気をつけます(汗)
  • 気になる質問をクリップする

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

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

    クリップを取り消します

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

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

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

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

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

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

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

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

    質問の評価を下げる

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

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

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

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

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

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

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

    詳細な説明はこちら

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

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

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

回答 6

checkベストアンサー

+3

DOM要素が読み込めていないために起きているエラーです。
setSelectYear()でset系の関数を全て呼んでいるので呼ぶ必要があるのはこれだけです。
winsow.onloadでDOMが読み込み終わってからsetSelectYear()を呼ぶといいんじゃないですかね。
以下全文
var Now = new Date();
var NowYear = Now.getFullYear();

window.onload = function(){
    setSelectYear();
}

function check(){
    //変数に入力された文字列から文字列の前後にある空白文字を抜いて格納。
    var nametxt = document.registration.name.value.replace(/(^\s+)|(\s+$)/g, "");
    var fromtxt = document.registration.from.value.replace(/(^\s+)|(\s+$)/g, "");
    var telltxt = document.registration.tel.value.replace(/(^\s+)|(\s+$)/g, "");

    //名前欄が未入力・空白の時にアラートを表示し、フォーカスする。
    if(nametxt == ""){
        window.alert("名前が未入力です");
        document.registration.name.focus();
        return false;

    //住所欄が未入力・空白の時にアラートを表示し、フォーカスする。
    }else if(fromtxt == ""){
        window.alert("住所が未入力です");
        document.registration.from.focus();
        return false;

    //電話番号欄が未入力・空白の時にアラートを表示し、フォーカスする。
    }else if(telltxt == ""){
        window.alert("電話番号が未入力です");
        document.registration.tel.focus();
        return false;

    //電話番号欄の文字列が数字ではない時にアラートを表示し、フォーカスする。
    }else if(telltxt.match(/[^0-9]+/)){
        window.alert("電話番号に数字以外の文字が入力されています")
        document.registration.tel.focus();
        return false;

    //未入力・空白項目がなく、電話番号に数字以外の文字列も入力されていない場合はtrueを送り処理を完了させる。
    }else{
        return true;
    }
}

/*[ オプションを更新(年) ]*/
function setSelectYear(){
    for(var y = NowYear-40; y <= NowYear-17; y++){

        //selectボックスIDからElementの取得
        var selectElement = document.getElementById("selectYear");

        //<option>要素を追加
        var option = document.createElement("option");
        //optionのvalue属性を設定
        option.value = y;
        //リストに表示するテキストの設定
        option.text = y;
        //セレクトボックスにオプションを追加
        selectElement.appendChild(option);
    }
    setSelectMonth();

}

/*[ オプションを更新(月) ]*/
function setSelectMonth(){
    var selectElement = document.getElementById("selectMonth");
    var child;

    //セレクトボックスの子要素を取得しつつループ
    while(child = selectElement.firstChild){ 
        //セレクトボックスから子要素を削除
        selectElement.removeChild(child); 
    }

    for(var m = 1; m <= 12; m++){
        var option = document.createElement("option");
        option.value = m;
        option.text = m;

        selectElement.appendChild(option);

    }
    setSelectDate();
}

/*[ オプションを更新(日) ]*/
function setSelectDate(){
    //選択された年を取得
    var Year =
    document.registration.selectYear.options[
    document.registration.selectYear.selectedIndex].value;
    //選択された月を取得
    var Month =
    document.registration.selectMonth.options[
    document.registration.selectMonth.selectedIndex].value;

    //うるう年に対応出来る月の最終日を取得
    var lastDate = new Date(Year,Month,0).getDate();

    var selectElement = document.getElementById("selectDate");
    var child;
    while(child = selectElement.firstChild){
        selectElement.removeChild(child);
    }
    for(var d = 1; d <= lastDate; d++){
        var option = document.createElement("option");
        option.value = d;
        option.text = d;
        selectElement.appendChild(option);
    }
}

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/05/27 18:04

    なるほど、Yearを呼ぶ位置が変なとこにあったんですね。。。
    呼ぶのはYearだけで全部連動するのですね、やっと説明出来ない箇所がなくなりました。
    ありがとう御座います♪

    キャンセル

+2

動かなくなった原因はスクリプトが実行されるタイミングが早まったためです。
まだ、DOM(画面の要素など)が準備ができていない段階でjavascriptが実行され、document.getElementByIdによる要素の取得が失敗しています。

エラーを回避するには、DOMの準備が完了してからスクリプトが実行されるようにすべきです。「window.onload」で検索するといいでしょう。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

+2

HTMLが読み込まれる前にjavascriptが走ってしまって、
ID=selectYearが読み込めないかと思います。

ですので、HTMLを読み込んでから実行するように

window.onload = function(){
    setSelectYear();
    setSelectMonth();
};

にしては如何でしょう?

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/05/29 09:24

    具体的な手段をありがとうございます♪
    他の方の回答と照らし合わせながら参照すると、
    どうやらYearの中でMonthの呼び出しはできてるので、
    onloadするのはYearだけで良さそうですね。

    キャンセル

+2

特に何もせずにスクリプトを書いた場合、それはその場で実行されます。つまり、まだ<head>の段階で実行されてしまうと、下にあるドロップダウンなどのフォームが読み込まれていない状態なので、エラーになります。素直に元の位置においておくか、onloadなど適当なタイミングで実行されるようにしましょう。

なお、

setSelectYear();//★★★この存在意義がわからなかった★★★
ですが、この上で作った関数を呼び出しています。関数は定義しただけだと、何も起きません

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/05/27 18:06

    関数は自然に実行されはしないのですね。
    モヤモヤがなくなりました。ありがとうございます。

    キャンセル

+1

そもそもhead内に記載するのが良いのかは場合によるかと。
動かない理由はみなさんが言っている通り、実行タイミングが変わったからです。
イメージ的には荷物を取りに行ったけど荷物が無くてエラーみたいな感じですかね。
つまり取りに行く先が用意できるまで待つ必要があります。
その場合いくつか方法があり、その一つがbodyの閉じタグ前での定義です。

window.onloadを使用する方法やaddEventListenerやattachEventでloadイベントをセットする方法がありますが前者は最良の方法とは言えないと思われます。
後者はブラウザ間実装の違いがあります(jQueryなどのライブラリはその差異を吸収し動作します)。
body閉じタグ前での宣言はデメリットらしいデメリットがないので選択肢の一つとして割と優秀でありだと思います。
また少し前からbody閉じタグ前でスクリプトを使用するのが一番いいのではないかという意見が出始めているように思います。
(理由としましては最後にJSを実行することで表示を早くすることにつながる。loadイベントのブラウザ間差異を気にしなくてよくなることなど)

何か参考になれば

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/05/29 09:32

    別サイドからの視点をありがとう御座います。
    選択肢が広がる様なアドバイスはとても参考になります。

    scriptが先なサンプルとbodyを閉じる寸前に書く例とあったので非常に混乱していたのですが、そういう背景があったのですね。

    新米初心者の目線で見ると、
    今回みたいなエラーも未然に回避出来るのに、
    なぜscriptを先に書く風潮があったのかが不思議でなりません。

    キャンセル

  • 2015/05/29 09:48

    私は初級者から中級者の間辺り(だといいの)です。
    それ以前はHTMLファイルにJSのコードを直書きするのが主流だったようです。
    先頭で読み込むのはこれも場合によりますよね、CSSファイルなら先頭の方がいいでしょう。なぜなら読み込みが完了するまでCSSで定義されたデザインが反映されないということにつながりますし。つまりJSでもページが読み込みされる(正確にはDOMが構築される前に)実行されてほしいものはHTMLの先頭辺りにおいておくといい訳ですね。

    速度について反例があったのでURLを載せておきます。
    http://memocarilog.info/jquery/5842

    キャンセル

  • 2015/05/29 11:02

    CSSはまだ触れておりません。
    扱う時の参考にします。
    もしかしたらチームで扱う時に上だったり下だったり人によって違うと嫌だから、
    CSSに合わせて上にしろって感じの流れかもしれませんね。

    参考URL読みました。
    なるほど、速度に関しては色々説は上がってるんですね。
    まぁコードの数はちょっとでも減らしたいですし、
    scriptの場合は、基本的に下、先に読み込ませたい例外の時は上、、、って感じが僕的にはしっくりです。

    キャンセル

0

なぜscriptの位置を動かしただけでエラーが発生したのか。 
見たところ、「位置を動かしただけ」ではないようですね。
まずはそのままコピペしてみてはいかがでしょう?

このエラーが出ている★箇所は本来どういう目的で作用していて、 
どう対応すれば本来の動きに戻るか。 

setSelectMonth();//★★★ここで止まる★★★
を消せばうごくのではないでしょうか?

function hogehoge(){・・・}
はこういう動きをしますよ~という定義をしているだけなので、
これだけではJSは実行されません。

hogehoge();
と書くことで関数を実行します。


スクリプトの流れとしては
setSelectYear()の中でsetSelectMonth()が実行され、
setSelectMonth()の中でsetSelectDate()が実行されています。

なので、
setSelectYear();
と書けば、setSelectMonth()もsetSelectDate()も実行されるということです。

投稿

  • 回答の評価を上げる

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

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

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

  • 回答の評価を下げる

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

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

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

  • 2015/05/27 18:02

    質問で★を付け足す時に一回そこを削除してしまい、
    書き直す時にMonthになっちゃっていたみたいです。
    Yearの間違いです。

    上の方でsetSelectYearを呼び出せば良かったのですね!
    何とかなりました。ありがとう御座います。

    キャンセル

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

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

関連した質問

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

  • JavaScript

    15883questions

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