6

When using Rails 7 with import maps, where do I put code that should be executed by one view only?

Specifically, I have a view that needs to run some Javascript code on load. My Javascript looks something like this:

import {TheController} from "./TheController"

let controller = new TheController();

document.onreadystatechange = function () {
  if (document.readyState === 'complete') {
    controller.onLoad();
  }
};  

How do I setup the Javascript environment so that the document.onreadystatechange code is executed only by the desired view? (Everything almost works when I put this code in a file imported by application.js, but then it gets executed by every view.)

I suspect the answer is to create separate importmaps and importmap_tags; but, I can find any demonstrations of how to do that in Rails 7.

Zack
  • 6,232
  • 8
  • 38
  • 68

3 Answers3

14

As @Azrklm points out, the answer is contained in this video https://youtu.be/PtxZvFnL2i0?t=1287 beginning at time 21:38.

Suppose we have some JavaScript that we want to run only on a view called FancyView. Here are the steps

  1. Place the code unique to FancyView in its own file, say FancyView.js (and remove it from application.js, if necessary).

  2. Add a line for FancyView.js to the importmap: pin "FancyView"

  3. Add the line <%= yield :head %> to application.html.erb`. (This tells Rails that individual views/layouts may want to add additional information to the web page's head.)

    <%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>
    <%= javascript_importmap_tags %> <%# This loads application.js %>
    <%= yield :head %>
    
  4. Add a javascript_import_module_tag to the view:

    <% content_for :head do %>
      <%= javascript_import_module_tag "FancyView" %>
    <% end %>
    
rogerkk
  • 5,494
  • 5
  • 37
  • 53
Zack
  • 6,232
  • 8
  • 38
  • 68
  • Can anybody tell why the code following step 4 isn't formatted? I highlighted it and clicked the {} button in the editor (several times). It also appears to be indented 4 spaces. – Zack Feb 15 '22 at 12:51
  • Not sure why this happened in the first place, but it seemed like the code in step 4 was indented one space to little to be interpreted as a code block. Fixed it for you! – rogerkk Feb 17 '22 at 04:29
  • But the javascript code is executed only once. – Run Feb 23 '22 at 02:23
  • I'm not sure what you mean. – Zack Feb 23 '22 at 13:37
  • If the page is using a Stimulus Controller you could also just import FancyView when that controller loads....correct? – hellion Apr 25 '22 at 17:36
2

If anyone has a similar problem finds this question, I found the answer from @Zack to be perfectly concise and exactly what I needed, BUT with 2 important caveats:

  1. I couldn't use the capcase naming convention for my js. FancyView needed to be fancyView.

  2. The javascript_import_module_tag should come after your javascript_importmap_tags

    <%= javascript_importmap_tags %>
    <%= yield(:head) %>
    

This is also now explained on the rails github page: https://github.com/rails/importmap-rails#selectively-importing-modules

Thanks @Zack!

Jason N
  • 37
  • 1
  • 5
0

DHH explains it pretty well have a look plz https://youtu.be/PtxZvFnL2i0?t=1287

Jr. dhh
  • 23
  • 6
  • To make this more useful (and receive more upvotes) you probably want to include the actual solution in your answer as well. – rogerkk Feb 11 '22 at 09:01
  • I myself exploring from last 2 days, How can I bring a simple bootstrap theme into rails 7 and can't figure out where to put the CSS and JS Although, a find a small guide which may help others in accordance with their problem. Kindly have a look at the following link: https://kmitov.com/posts/rails-7-with-bootstrap-5-by-cssbundling-rails-with-dart-sass-and-jsbundling-rails-with-esbuild-no-webpack-and-webpacker-and-a-salt-of-stimulus/ – Jr. dhh Feb 11 '22 at 10:20