using controller variable in javascript in phoenix - javascript

Is it possible to use a variable which is passed from controller to view in render parameters to be used in javascript and how to do it?

The variable passed from controllers can be used in javascript as following:
<script type="text/javascript">
alert("<%= #var %>")
</script>

Another way you can use PhoenixGon it generates script tag with variables and additional methods for simplicity. It generate all stuff for you. You only need to use it from window.Gon or wundow.YouApplicationNamespace. And you don't need other rendering and data attributing in html.
In controller:
def index(conn, _params) do
conn = put_gon(conn, :variable, :value)
render conn, "index.html"
end
In js module or browser console:
window.Gon.getAsset('variable')
# => 'value'
It also keeps Mix.env for using in js.

Related

Pass instance variable to js Rails

In my search controller I have an instance variable, #results. I set it to return a dummy result, 'foo'.
In my search.html.erb view... I set window.results = <%= raw #results.to_json %>.
At the top of my search.js asset file, I console.log(results) and get undefined, but when I get into the devtools after the page load, results is populated with 'foo'. The console.log statement is also wrapped in a jquery ready function.
What gives?
Rails assets are precompiled so they don't have access to instance variables coming from the controller. Embed the Javascript directly into your view using a script tag and access the #results just like you did. You could also initiate a call to an external Javascript file.

How to get rails controller variable in js file

I have a variable in rails controller like
def index
#approveflag = true
end
I need to access this variable in my javascript code, I used the code given below
in index.html.erb
<script>
alert("<%=#approveflag%>")
<script>
It works fine with result "true".But when I moved this code to its corresponding .js file it gives an alert with result string ""<%=#approveflag%>"".
What is the reason. How can I solve this?
Thanks in advance.
I personally don't like mixing js with erb so I would do something like this:
in index.html.erb
<%= content_tag :div, '', id: 'mycontainer', data: { source: #approveflag } %>
in js
$('#mycontainer').data('source')
alert($('#mycontainer').data('source'))
And you have the value from that instance variable, you can add a data attribute in a link_to if you want.
You cannot use the js files for this, they are part of the asset pipeline, they are compiled/compressed, and preferably only downloaded once by your client (browser). So they should not change. So at the time the js-files are precompiled, the instance variable is not set and would not make any sense anyway.
But there are a few options.
You can declare a javascript variable in your view, which your javascript can use (for global data)
Code (I use haml):
:javascript
var approveFlag = #{#approveflag} ;
You can declare data-tags on elements, if the data belongs to a specific element. But for instance, you could also a data-tag on body element
For instance
%body{:'data-approveflag' => #approveflag}
Or something like
= link_to 'Collapse', '#', 'data-collapse-div' => 'class-to-collapse'
Alternatively you can use ajax/json to download the data. This is clean, but adds an extra delay, so only do this is if the data is not required immediately.
I recommend that you to use the 'gon' gem
I'm usually more oriented to straight options that don't imply installing, but trust me using 'gon' is very direct and clean
In your Gemfile add this lines
# To use controller variables as javascript variables
gem 'gon'
Do a bundle install to get/install the gem
In your app/views/layouts/application.html.erb add the following line
<%= include_gon %>
Then in your controller pass your variable to gon as simple as this
gon.your_variable = #controller_variable
And in your javascripts retrieve your variable (in this case to show an alert)
alert (gon.your_variable) ;
And That's it !
For more examples and details see the Wiki page - https://github.com/gazay/gon/wiki
In my project I need sometimes user language related translations. So what I did is, I created a simple js file to store the localized text:
var TRANSLATION_ARRAY = []
function store_translation(key, value) {
TRANSLATION_ARRAY[key] = value
}
function get_translation(key) {
return TRANSLATION_ARRAY[key]
}
In den index.html.erb or other components I do this to store the localized text:
store_translation('text_id', "<%= translate_with_user_language('text_id') %>")
In my plain js file located in app/assets/javascripts i get the localized text by:
get_translation('text_id')
Works very well. You can use this approach also for other purposes not only translations.

Defining Django context variable in Jquery giving me error?

I am trying to use a django context variable in my jquery script.
First of all, this WORKS:
index.html
<head>
<script type="text/javascript">
var page_size = {{page_obj.paginator.num_pages}};
</script>
<script type="text/javascript" src="{% static 'js/paginate.js' %}"></script>
</head>
js/paginate.js
$(document).ready( function() {
alert(page_size); //THIS WORKS!!!
});
However, I didn't want the users to be able to be view my variables so I simply added the global variable declaration in my "paginate.js" file:
index.html
<head>
<script type="text/javascript" src="{% static 'js/paginate.js' %}"></script>
</head>
js/paginate.js
var page_size = {{page_obj.paginator.num_pages}}; //Exactly the same as the above!!
$(document).ready( function() {
alert(page_size); //ERROR!!!
});
Strangely enough, this gives me an error:
SyntaxError: invalid property id
var page_size = {{page_obj.paginator.num_pages}};
I have no idea why the first one works while the second one gives me an error, because they are exactly the same... Maybe because I'm second one is declaration in Jquery..?? Any idea??
Thanks..
TL;DR
You can't pass a variable to a static files because they aren't parse by the Django template processor.
Explanations
Your first example works because you set the {{ page_obj.paginator.num_pages }} in your template, which will be parsed and transform into a number. When you're returning a template with Django (through any render method), only the template will be rendered. CSS and Javascript linked in your template are called static files: that means they're ressources which will not be read by the Django template processor.
Imagine that you want to insert your variable in an img in your page. Does it makes any sense? No? However, it's the same behavior.
How to do this then?
You can get the data either via an AJAX request in your Javascript file (warning: a bit overkill for your case here), or using your first method.
Related topic:
Passing Python Data to JavaScript via Django
Passing parameters to the Javascript code on a page using django templates?
In Django, if we need to pass variables from a view to a JS/html file, we'll have to ensure that the file is parsed by the django template engine. In other words the file has to be served by Django.
Whereas here, the included Javascript isn't processed by the Django template processor on the server, so that won't work.
If you need to pass template variables to be used in JS files, then you have to use the first method mentioned in the question i.e. create a small <script> block wherein some global variable is declared to contain those template variables. Then, any JS file can get the values by looking for the global js variable.

Grails 2.0: Use Service in javascript function in GSP

I am just wondering how I can call a method of a service from within a function within a GSP. I tried the following but it does not seem to work:
<%# page import="com.company.MyService" %>
<%
def myService =grailsApplication.classLoader.loadClass('com.company.MyService').newInstance()
%>
<html>
<head>
[...]
<script language="javascript">
function myFunction() {
if (${myservice.isSomethingAvailable()}) {
[...]
}
}
</script>
I am pretty new to javascript and Grails. Not sure how to achieve that or if it's even possible. Any help appreciated.
Thanks a lot
Jonas
loadClass().newInstance() creates new instance of object, not spring bean (i mean it's not tied to grails infrastructure), i'm sure it's not what you want
You can pass service from your controller, like render(model: [myService: myService]) (you have to declare it at controller lever)
It's much more correct way is to pass result of this call, not service itself. I mean: render(model: [isSomethingAvailable: myService.isSomethingAvailable]) and test it as if ($(isSomethingAvailable)) {
Notice that gsp is processed in server-side, not client-size. So it doesn't matter where you use your variable - on javascript code, or html code. And also, you can use gsp if tag: <g:if test="${isSomethingAvailable}"> instead of preparing javascript to check value on client-side (because you already know the result)

Accessing rails routes in javascript

Can anyone explain how i can access the rails routes/names routes in javascript ?
The following are some of the things i tried
http://github.com/jsierles/js_named_routes.
but no luck.
I was researching this question for a while and didn't found any implementation compatible with Rails 3.
So decided to write my own:
https://github.com/railsware/js-routes
kishore I think this is the simpliest way, just call:
Rails.application.routes.url_helpers.*_path
So, if you have in your routes.rb, let's say:
resources :users
then you want to call the index action from a javascript file, you do:
$.get('<%= Rails.application.routes.url_helpers.users_path %>', function(data){ ...
Take into account that the js file should have a .erb extension (or *.js.erb) so rails knows that must be preprocessed. Otherwise, the file will be served as is.
If I understand your requirement correctly you want Javascript code in your views to have access to the named routes. If so, then one simple way to do this is to render your Javascript code through a template (ERB, Haml, etc) and then to expand the routes something like the following:
ERB:
<script>
$.get('<%= some_named_route_path %>', function(data) {
});
</script>
Haml:
:javascript
$.get('#{ some_named_route_path }', function(data) {
});
UPDATE: Adding suggestions for public/javascripts/ case
Accessing named routes from the public folder is a bit trickier but there at least 2 ways that come to mind, neither of which is entirely satisfactory but, one or either of which might suit your application
Create javascript templates in (say) lib/javascripts using ERB named like '*.js.erb' and a rake task to expand those templates into public/javascripts before deploying (say as a step in your Capistrano recipe for example). Downside of that is that your changes are not made available live on the site until the templates are expanded and you might not get the right syntax highlighting of your javascript with an .erb extension file
Create per-view javascript helper functions in a content_for :head block which expand the named routes and make those available to code from your public javascript files. If you're careful with namespacing and conventions this might work out well. The downside is that the code calling these javascript helpers is decoupled from the code that defines them which could be confusing for maintainers or prone to abuse.
In some view:
<% content_for :head do %>
<script>
SomeNameSpace.helper_to_some_named_route = function() {
return '%<= some_named_route_path %>
};
</script>
<% end %>
Then in public/application.js (say)
$.get(SomeNameSpace.helper_to_some_named_route(), function(data) {
});
bjg really answered this, but I thought I'd extract the relevant part and amplify with an example.
You simply provide your view a string variable whose value is a named Rails path, and then use that value in the Javascript of your form. An example that illustrates how a controller method can specify the path for another method, to be opened by the script on the press of a button:
File config/routes.rb:
...
resource :foo, :only => [:show, :reset]
...
match 'foo_reset_path' => 'foo#reset'
Commanding rake routes will now produce, among other output, this:
foo GET /foo(.:format) foo#show
foo_reset_path /foo_reset_path(.:format) foo#reset
foo_reset_path is what we're going to use here, but you can of course use this method with any named Rails path.
File app/controllers/foo_controller.rb:
...
def show
#reset_path = "foo_reset_path" # simply the string you'd use in the
# Rails code for opening the path
...
end
...
def reset
... # reset some variables to their default values
redirect_to foo_path # causes the show method to be called, and the HTML
# page to be redisplayed
end
File app/views/foo/show.html.erb:
...
<input type="hidden" id="reset_path" name="reset_path" value="<%= #reset_path %>">
...
<script>
$(document).ready(function() {
...
/* Hang functionality on the "Reset form" button. */
$('#reset_button').click(function () {
var reset_path = $('#reset_path').val();
window.open(reset_path, "_self")
});
...
})
</script>
I'm using JQuery here, but the basic idea should be clear. The script adds a hook to the button element whose id is reset_button, so that clicking on the button causes the reset method of foo_controller to be called.
What I did based on Teemu's great answer:
In your controller:
def show
#section = Section.find(params[:id])
respond_to do |format|
format.html
format.json { render json: #section}
end
end
In your view:
<input type="hidden" id="section_path" data-path="<%= #section.id %>" name="section_path" value="foo">
In your js:
var id = $('#section_path').attr('data-path');
$.ajax({
url:'/sections/'+ id +'.json',
type:"GET",
success: function (data){
console.info(data);
},
error: function (xhr, status){
console.info(xhr.error);
}
});
If you are using a JS pipeline that supports import (ES6 + webpacker), you might want to check out js_from_routes, a code-generation library that works seamlessly with Rails reloader.
For each endpoint that you'd like to access from JS, it will generate a method that can help you build a URL or make a request.
resources :video_clips, only: [:update], export: true
By using it in combination with axios, these generated helpers can be convenient and easy to use:
import VideoClipsRequests from '#requests/VideoClipsRequests'
VideoClipsRequests.update({ data: video })
.then(onVideoUpdate)
Have in mind that you can adjust the generated code by providing a custom template, so it can adapt to any technology you are using, even plain jQuery.
Benefits:
No need to manually specify the URL, preventing mistakes and saving development time.
If an action is renamed or removed, the helper ceases to exist, which causes an error that is easier to detect than a 404.
See http://tore.darell.no/pages/javascript_routes:
JavascriptRoutes converts your Rails routes into JavaScript. You can then access (generate) them in the browser (or any other JS environment). It supports both normal and named routes, and creates helper functions for the latter.
Update: It looks as though someone has forked this if you prefer jQuery: https://github.com/ajnsit/javascript_routes
gem install the "angular_rails_templates"
Create a file called angular_rails_templates.rb in the config/initializers folder
copy following code in the file and restart server. (including "module CustomERBEngine" for it cannot be added to code block by 4 space)
module CustomERBEngine
class ERBTemplate < Tilt::ERBTemplate
def evaluate(scope, locals, &block)
scope.class_eval do
include Rails.application.routes.url_helpers
include Rails.application.routes.mounted_helpers
include ActionView::Helpers
end
super
end
end
end
Tilt.register CustomERBEngine::ERBTemplate, '.erb'

Categories

Resources