Sven Kirsten
Sven Kirsten

Reputation: 518

How to call a javascript function inside a rails view?

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 !

Upvotes: 1

Views: 3853

Answers (2)

smithWEBtek
smithWEBtek

Reputation: 111

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.

Upvotes: 0

rmhunter
rmhunter

Reputation: 581

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();
});

Upvotes: 1

Related Questions