Fin_IT

FinanceとITに関する記事をメインに。

RailsでJavaScriptが機能しない時の対策

今回はRailsJavaScriptが機能しない時の解決方法となりえる対策を一つ紹介いたします。
以下の流れに沿って解説していきます。
Ⅰ問題の把握
Ⅱ問題の原因
Ⅲ解決方法



Ⅰ問題の把握
説明として用意するファイルは以下の通りです
①index.html.erb(自作)
②test.js(自作)
③application.js(rails newコマンドでデフォルトに存在)
④application.html.erb(rails newコマンドでデフォルトに存在)
今回は、index.htmlにある内容を、外部ファイルであるtest.jsにてhtmlの内容を変更することを目指します
各ファイルの詳細は以下の通りです
index.html.erb

<p id = 'hello'>
Hello World
</p>

test.js

document.getElementById('hello').textContent = "Hello JavaScript"

application.js

// This is a manifest file that'll be compiled into application.js, which will include all the files
// listed below.

// Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
// or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.

// It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
// compiled file. JavaScript code in this file should be added after the last require_* statement.

// Read Sprockets README (https://github.com/rails/sprockets#sprockets-directives) for details
// about supported directives.

// = require jquery
// = require jquery_ujs
// = require turbolinks
// = require_tree .

application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title>SampleApp</title>
    <%= csrf_meta_tags %>

    <%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_include_tag 'application', 'data-turbolinks-track': 'reload' %>
    </head>

  <body>
     <%= yield %>
  </body>
  </html>

尚、applicaiton.js や application.html.erb の概要を良く知らない方は下記記事にて詳細に書いているのでご参照ください。
stock-study.hatenablog.com

これで原理的には、index.htmlに書いた内容である 「Hello World」という文字列が、test.jsに書いたコードによって「Hello Javascript」に書き換えられているはずですが、、、、
やってみるとわかる通り書き換えられず以下のようなエラーがコンソール上にて確認されます
f:id:stock_study:20200412152607p:plain
このエラーは「何もない要素の中から、textContentを指定できないよ」という意味です。
しかし、こちらはちゃんとindex.html中にid付けも行ったし、test.jsにてid指定も行ったのに要素がないとはどういうことだ??となりますよね。
以下ではなぜこのような現象が起きたのかについて解説したいと思います


Ⅱ問題の原因
なぜ、このような現象が起こったかと言いますと、ズバリ、JavaScriptは読み込まれた段階で実行されるためです。
今回の場合で言えば読み込まれた段階で要素

<p id ="hello"> Hello World </p>

が定義されていなかったことに原因があります。
今回の場合JavaScriptはapplicaton.html.erb中の

<%= stylesheet_link_tag    'application', media: 'all', 'data-turbolinks-track': 'reload' %>

にて実行されますが要素を定義しているindex.htmlはその下の

 <body>
     
     <%= yield %>
    
  </body>

中のyieldに配置されます。すなわち。jsの実行段階では何も定義されていないことになるため、先のようなエラーが発生したのです
解説図
f:id:stock_study:20200412153754p:plain
Ⅲ解決方法
それではどのようにすれば、JavaScriptを機能させることができるのでしょうか?
それはJavaScriptが実行するタイミングをずらすことです。
先ほど述べた通り通常は読み込みとともに実行をするのですが、タイミングをページが完全に読み込まれた後に実行するようにすると、どこに記述しようが一旦はすべての内容がロードされるまで待機状態になるため機能するようになります。
タイミングをずらすには以下のコードを用います。

onload = function(){
//ここにjsコード記述
}

今回の例でいえば下記のようになります

onload= function(){
document.getElementById('hello').textContent = "Hello JavaScript"
}

f:id:stock_study:20200412154718p:plain
無事に実行されました。
まとめると、
JavaScriptは読み込まれた段階で実行されることに気を付けないと要素が無いというエラーが発生する
②実行するタイミングをずらすには onload = function(){}を用いると便利

ということです。
ご参考になれば幸いです