3

I am learning JavaScript and trying to use it with Ruby on Rails. I have default Rails project structure and I have created a simple assets/javascript/test.js file.

assets/javascript/test.js:

elements = document.getElementsByTagName('BODY'); console.log(elements[0]); 

The result in console is undefined, but when i add next code:

var elements = document.getElementsByTagName('*'); for (var i = 0; i < elements.length; i++) { document.writeln(elements[i].tagName); } elements = document.getElementsByTagName('BODY'); console.log(elements[0]); 

The result is as expected - body tag. Can u please explain what's going on and how to access body tag and its elements from js right?

Using:

console.log (document.body); 

also shows null in console.

2
  • can't you just use document.body? --> developer.mozilla.org/en-US/docs/Web/API/Document/bodyCommentedNov 13, 2015 at 21:04
  • i've tried it, but had same issue - null in console. May be it is because i initialize my js file in header of my application.html.erb? and when js is being processed, body tag has not been initialized yet? But i haven't modified it... Rails generates it like this
    – D. Rakov
    CommentedNov 13, 2015 at 21:10

1 Answer 1

3

You need to wrap your JS inside of DOM ready event:

$(document).ready(function() { //your code goes here }); 

In case of Rails with Turbolinks:

.coffee

ready = -> //your coffeescript goes here $(document).ready(ready) $(document).on('page:load', ready) 

.js

var ready = function() { //your javascript goes here }; $(document).ready(ready); $(document).on('page:load', ready); 

Your assets/javascript/test.js file:

var ready = function() { console.log(document.body); }; $(document).ready(ready); $(document).on('page:load', ready); 

Explanation:

From Using jQuery Core :

A page can't be manipulated safely until the document is "ready." jQuery detects this state of readiness for you. Code included inside $( document ).ready() will only run once the page Document Object Model (DOM) is ready for JavaScript code to execute. Code included inside $( window ).load(function() { ... }) will run once the entire page (images or iframes), not just the DOM, is ready.

JS is executed as soon as it is encountered in your document. Rails usually imports your JS via application.js file which loaded in the head of your document. At this point the rest of your document hasn't been even loaded so JS executes and finds partial unfinished DOM - body hasn't been rendered yet.

To postpone execution of your JS you can wrap it - aka register it - with $(document).ready event. You can have multiple calls to $(document).ready across multiple files. Usually it is a good idea to wrap your files with it.

When entire document is loaded, all you DOM elements has been loaded, jQuery will fire ready event and all your code registered with $(document).ready will get executed.

Turbolinks

From Working with JavaScript in Rails # Turbolinks:

Turbolinks attaches a click handler to all <a> on the page. If your browser supports PushState, Turbolinks will make an Ajax request for the page, parse the response, and replace the entire of the page with the of the response. It will then use PushState to change the URL to the correct one, preserving refresh semantics and giving you pretty URLs.

When writing CoffeeScript, you'll often want to do some sort of processing upon page load. With jQuery, you'd write something like this:

$(document).ready -> alert "page has loaded!" 

However, because Turbolinks overrides the normal page loading process, the event that this relies on will not be fired. If you have code that looks like this, you must change your code to do this instead:

$(document).on "page:change", -> alert "page has loaded!" 

Resources:

1
  • Yeah! It works, thanks, can you describe this issue?
    – D. Rakov
    CommentedNov 14, 2015 at 11:51

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.