Ruby on Rails - Send JavaScript variable from controller to external Javascript asset file
Asked Answered
R

2

12

I am creating a website in Ruby on Rails. I have a controller action that renders a view like so:

def show
  time_left = Time.now.to_i - 3.hours.to_i
  @character = current_user.characters.find(params[:id])
  respond_to do |format|
    format.html # show.html.erb
    format.xml  { render :xml => @character }
  end
end

This is fine as it renders the show.html.erb as I like. I would like however to somehow pass time_left to the view as a Javascript variable as this value is use by a countdown JQuery plugin.

I could put a javascript block on the page in the HTML and print a instance variable out like so:

<script type="javascript"> $('#countdown').countdown('<%= @time_left =>')</script>

But I would like to keep all my JS in a external file and off the page could anyone give some advice on how to implement this?

Revolution answered 27/4, 2010 at 14:9 Comment(1)
Related: #2465466‌​n-in-rails-viewDolliedolloff
D
9

Yes, you can!

Rewrite your JS code into function with one argument (timelimit) and put it into some external file. Then you can call the function from view and pass that @timeleft variable as JS function argument.

Short example:

#controller
@time_left = Time.now.to_i - 3.hours.to_i

.

#javascript
function count_down(time_left) {
  $('#countdown').countdown(time_left)
}

.

#view
<%=javascript_tag "count_down(#{@time_left})" -%>

javascript_tag

Example not tested, it is only idea not complete solution. Don't forget to load that JS file. You can use other JS rails helper javascript_include_tag.

Defeasance answered 27/4, 2010 at 14:16 Comment(1)
Actually today I would suggest to use meta tag attribute to pass variables into the page. You can read those attributes via javascript easily.Defeasance
D
5

retro's technique of using a function parameter is a possibility, but you have to properly escape the variable you are passing with either escape_javascript or to_json + html_safe as explained below.

However, since you want to affect external files, the best techniques will be to use gon. Another good possibility is to use data- attributes.

gon

Gem specialized for the job: https://github.com/gazay/gon

Probably the most robust solution.

Gemfile:

gem 'gon'

Controller:

gon.timeleft = 1

Layout app/views/layouts/application.html.erb:

<html>
<head>
  <meta charset="utf-8"/>
  <%= include_gon %>
  <%= javascript_include_tag 'application' %>

Asset file:

gon.timeleft === 1

data- attributes

Add values to attributes, retrieve them with JavaScript DOM operations.

Sometimes called "unobtrusive Javascript".

View head:

<%= javascript_include_tag 'application' %>

View body:

<%= content_tag 'div', '', id: 'data', data: {timeleft: '1'} %>

Asset file:

$(function() {
  parseInt($('#data').data('key1')) === 1
})

The following illustrate how escape_javascript and to_json work for you to use on top of retro's answer.

escape_javascript

Alias: j.

Works only on strings.

Escapes characters that can have special meanings in JavaScript strings, like backslash escapes, into a format suitable to put inside JavaScript string literal quotes.

Maintains html_safe status of input, so needs html_safe otherwise special HTML chars like < would get escaped into &lt;.

<% a = "\\n<" %>
<%= javascript_tag do %>
  f('<%= j(a)           %>') // === '\\n&lt;'
  f('<%= j(a).html_safe %>') // === '\\n<'
<% end %>

to_json + html_safe

Works because JSON is almost a subset of Javascript object literal notation.

Works not only on hash objects, but also on strings, arrays and integers which are converted to JSON fragments of the corresponding data type.

<% data = { key1: 'val1', key2: 'val2' } %>
<%= javascript_tag do %>
  var data = <%= data.to_json.html_safe %>
  f(data.key1) \\ === 'val1'
  f(data.key2) \\ === 'val2'
<% end %>
Dolliedolloff answered 2/11, 2014 at 12:27 Comment(2)
Thanks - if they're not duplicates then they deserve individual answersIllyes
data- attributes is simple and easy. Thank youAriannaarianne

© 2022 - 2024 — McMap. All rights reserved.