1

I did just a upgrade from RAILS 5 to RAILS 6 and I see that all rails views are not able to call a javascript function as before in RAILS 5.

I have an external javascript file located under

app/javascript/packs/station.js

This is is embeded in in app/views/layouts/application.html.erb as

<%= javascript_pack_tag 'station' %>

This is the code how I call the javascrpt function from html.erb file :

<%= text_field_tag(:station_text_field, ... ,
                    onkeyup: "javascript: request_stations(); ") %>

When I try to call a function thats is part of the station.js then I get an error in the browser developmer view: ReferenceError: request_stations is not defined

But I can also see in the brwoser view, under Debugger :

 Webpack / app/javascript / packs / station.js 
 and the javascript function I want to call.

So it seems that this script was loaded by the browser.

In contrast, when I just copy and paste these few lines that represent this javascript function direct into the template view file (...html.erb), something like :

<script>

function request_stations ()
{
    alert("calling request_stations");

};

</script>

then - it works as expected !

6
  • What if, instead of application.html.erb, you put <%= javascript_pack_tag 'station' %> in the specific view file that you need it in? (c.f., Adding a script that will be used by a specific file) Commented Jun 15, 2020 at 16:37
  • its the same behavior Commented Jun 15, 2020 at 17:05
  • In your browser, inspect the source using the dev tools and see if the javascript file is being included. I suspect that, for some reason, it's not. Commented Jun 15, 2020 at 17:07
  • What I already said, the browser was successfully loaded the javascript file. Commented Jun 15, 2020 at 17:10
  • You said that under the debugger, "... and the javascript function I want to call". What do you mean, exactly, by that? Are you able to call the function from the js console in the browser? Commented Jun 15, 2020 at 17:22

2 Answers 2

1

By default, variables/functions defined inside JavaScript files that are packed by Webpacker will not be available globally.

This is a good thing, because it prevents global naming conflicts. Generally speaking, you don't want to reference javascript functions/variables from your view. You instead want to write JavaScript in a way that attaches functionality to DOM nodes using their id or other attributes.

Here is a basic example based on the code you provided:

# in your rails view
<%= text_field_tag(:station_text_field, ..., id: 'station-text-field') %>
// in your javascript

function request_stations() {
    alert("calling request_stations");
};

const stationTextField = document.querySelector("#station-text-field");

stationTextField.addEventListener('keyup', (event) => {
    request_stations();
});
Sign up to request clarification or add additional context in comments.

2 Comments

I did an update of the question to show the HTML code how to call the function. This way works perfekcly in RAILS 5.
I don't know specifically why it worked for you in Rails 5, but I still would highly recommend not putting the event listener directly in your view unless you have to. I updated my example code to be relevant to the view code you added
0

Agree with mhunter's answer. This post helped me get a grounding on this difference in Rails 6: https://blog.capsens.eu/how-to-write-javascript-in-rails-6-webpacker-yarn-and-sprockets-cdf990387463

What I don't see in your question is whether or not you did this in app/javascript/packs/application.js:

require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("channels")

require("station")

The big difference in Rails 6 is that you have to deliberately:

    1. require a JS file
    1. deliberately export something from that file
    1. deliberately import that something, in the file where you want to use it.

So if there is a function in station.js that you want to use, connect the steps above. Start with a simple function in station.js that fires upon DOMContentLoaded, and add a console.log("hey, station.js is alive and well"). If you don't see it, then something in those 3 steps is not right.

In pre-Rails6, you had a "garden" of JavaScript, just by virtue of being in the asset pipeline. In Rails 6, you have to be more deliberate.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.