soniccool
soniccool

Reputation: 6058

How to call a JavaScript function from Rails 6 view

In my view I'm trying to call a JavaScript function which I've placed in application.js:

/* Set the width of the side navigation to 250px */
function openNav() {
  document.getElementById("mySidenav").style.width = "250px";
}

/* Set the width of the side navigation to 0 */
function closeNav() {
  document.getElementById("mySidenav").style.width = "0";
}

This is my HTML:

<div id="mySidenav" class="sidenav">
  <a href="javascript:void(0)" class="closebtn" onclick="closeNav()">&times;</a>
  <a href="#">About</a>
  <a href="#">Services</a>
  <a href="#">Clients</a>
  <a href="#">Contact</a>
</div>

<span style="font-size:30px;cursor:pointer" onclick="openNav()">&#9776; open</span>

If I put this in my view within <script></script> tags, then it works. My application.js works and it's being compiled but for some reason it only works if the JavaScript is in the actual view of the html.erb file. But if it's in application.js in my pack folder, although it builds the JavaScript file, it returns this error in the console:

(index):23 Uncaught ReferenceError: openNav is not defined
    at HTMLSpanElement.onclick ((index):23)

How can I get this to work in my pack/application.js file rather than having it in the theme in a <script> tag?

Upvotes: 1

Views: 1568

Answers (2)

James Garcia
James Garcia

Reputation: 31

It is unclear why the function openNav() does not work in Rails 6. I would suspect that it has to do with the changes from Sprockets to Webpacker. I did find a solution that may be more conventional than adding the methods to the "window" object. Adding methods or properties directly to the "window" object could inadvertently overwrite defaults. I took guidance from the RailsGuides.

https://edgeguides.rubyonrails.org/working_with_javascript_in_rails.html

I added an "id" to the Open and Close elements and removed their "onclick" properties. Adding the ids allowed me to target them in the side_nav.js file to add a "click" event listeners.

Index.html.erb

<div id="mySidenav" class="sidenav">
  <a href="#" class="closebtn" id="close-nav >&times;</a>
  <a href="#">About</a>
  <a href="#">Services</a>
  <a href="#">Clients</a>
  <a href="#">Contact</a>
</div>

<span id="open-nav>Open</span>

<%= javascript_pack_tag 'side_nav' %>

I am using Turbolinks, and so I wait to add the event listeners until after the Turbolinks loads to make sure that the DOM is finished rendering. This will make sure the "id" are available to be targeted. If you are not using Turbolinks you may be able to change it out for "DOMContentLoaded".

javascript\packs\side_nav.js

window.addEventListener("turbolinks:load", () => {
  // Open
  document.getElementById('open-nav').addEventListener("click", e => {
    e.preventDefault();
    document.getElementById("mySidenav").style.width = "250px";
  });

  // Close
  document.getElementById('close-nav').addEventListener("click", e => {
    e.preventDefault();
    document.getElementById("mySidenav").style.width = "0";
  });
});

Upvotes: 1

soniccool
soniccool

Reputation: 6058

"Rails 5/6: How to include JS functions with webpacker?" worked:

window.closeNav = function() {
  document.getElementById("mySidenav").style.width = "0";
}

window.openNav = function() {
  document.getElementById("mySidenav").style.width = "250px";
}

Can anyone explain why in Rails 6?

Upvotes: 4

Related Questions