Passing javascript variable into erb tag - javascript

I've been looking into how to use a javascript variable within erb <% %> tags. This will have to be done via AJAX (see How to pass a javascript variable into a erb code in a js view?). I'm quite new to JS and especially new to AJAX and finding an example of this in action would be awesome.
Consider the following simple scenario where all that is needed to be passed from the JS to the ERB is a simple bit of text:
HTML:
<input id="example-input" type="text">
$(function() {
$('input#example-input').keyup(function(e) {
if(e.keyCode == 13){
var input = $('input#example-input').val();
<% puts input.upcase %>
}
}
});
Notice that the input will not be defined within the erb tags, and hence this will throw an error.

I believe you're assuming that the line <% puts input.upcase %> will execute ruby code after your javascript line var input = $('input#example-input').val();. If that is what you were thinking, this is incorrect. In the example you've given:
The <% puts input.upcase %> gets executed when the page loads.
input in <% puts input.upcase %> is a ruby variable
input in var input = $('input#example-input').val(); is a javascript variable
If you had a variable that you set on the server side, you could say something like this in your javascript:
var my_js_var = '<%= a_str_in_ruby %>';
and that would work fine for intializing a variable on the javascript side.
However since you want to request data from the client side (aka javascript) to your server side (to be handled by rails controller), what you should be doing is submitting an ajax request. There's a section in the rails documentation that contains examples, and a good railscasts episode (if you're a paying member).

Related

Include a Coffeescript file with ERB in a view

This is giving me a major headache...
So I have an app which requires a sidebar that lists various information to do with a user's player. One section of this sidebar is a friends list. Now, when Player A sends a friend request to Player B, the request should be automatically logged in B's sidebar, and I intend to use WebSockets to do this.
Here is my cp.js.coffe.erb file (there's only a few snippets of ERB at the moment; there will be loads more and I rather get this working first):
$ ->
$("#cp").accordion()
if `"WebSocket" in window`
socket = new WebSocket("ws://localhost:8080")
socket.onopen = =>
console.log("Connection Open")
init = {
sender: "cp"
action: "init"
user: <%= #user.id %>
token: <%= cookies["remember_token"] %>
}
socket.send(init.to_json)
socket.onerror = (e)=>
console.log(e)
socket.onclose = =>
console.log("Closed")
socket.onmessage = (m)=>
console.log("Recieved: #{m.data}")
msg = m.data.JSON.parse
switch msg.action
when "ret_init"
when "friend_udt"
refreshFriend()
refreshFriend() ->
html = "<%= j render 'layouts/friends' %>"
$('#friends').empty()
$('#friends').add(html)
Theoretically, the code itself works fine, the problem being that Rails doesn't let you use ERB in the assets pipeline, and so this file has to sit in app/views/layouts.the file cannot access the variables declared within a controller or use the render method (or most other ERB methods).
Here's the thing: I can't include said file in my application.html.erb file, and I looked into requesting the file with AJAX, but from my understanding that will immediately execute the Javascript once and once only, and I need the methods in this to be constantly available to update the sidebar.
Is there any way of including this file so that it works with the ERB and the CoffeScript so that it would be continuously avaliable to the page? Am I misunderstanding the whole AJAX requesting method?
Thanks #nzifnab for your help with the JS. Now my friends partial looks like this:
<ul id="friendlist">
<% if Relation.find_by(owner: #user.id, type: "freq") != nil %>
<% Relation.find_by(owner: #user.id, type: "freq").each do |r| %>
<li class="friend-request-cp"><%= link_to "/#{User.find(r.character).name}" %></li>
<% end %>
<% end %>
<% if Relation.find_by(owner: #user.id, type: "friend") != nil %>
<% Relation.find_by(owner: #user.id, type: "friend").each do |r| %>
<li class="friend-cp"><%= link_to "/#{User.find(r.character).name}" %></li>
<% end %>
<% end %>
</ul>
I need to apply two different styles to each item, hence why I'm using the ERB here. This works fine, as it's loaded when the page is first navigated to, but my code was supposed to re-render that partial every time a notification comes through of any new interactions. It would then repopulate the list using the data from the database again. Is there a more efficient way of doing this? Can I still do this with the hamlcoffeeassets gem you showed me?
Slight tangent ensues:
By the way, I'm using Ruby 2.0.0-p247 and Rails 4 on Windows 7. I felt the need to include that because of some major compatibility issues with gems that are much different from Ubuntu. I had to move from Ubuntu to Windows because updating from 13.04 to 13.10 broke everything Ruby Gem on that OS. I don't have tome to find a fix: I literally have only four days to get this app built.
You can kinda use erb in the asset pipeline, but you have to remember that it only gets rendered ONCE, EVER, and not once for every user and so even if there was an #user variable (which there won't be), it would never change. You can use erb in your coffee file for things like route paths and environment variables, but not for things like user-specific config and dynamic changes to the JS. It's bad practice anyway.
What you should really do is use a javascript library to read cookies instead of trying to do it with rails (This will give you access to some of the things you appear to be trying to do). And when you need more dynamic behavior you should render data-attributes or other values into the html DOM itself and use the javascript to read that.
Take a look at this cookie library: https://github.com/carhartl/jquery-cookie
There's many others to look at via a quick google search.
socket.onopen = =>
console.log("Connection Open")
init = {
sender: "cp"
action: "init"
user: $.cookie('user_id')
token: $.cookie('remember_token')
}
There are a couple of ways to render new markup for your view using JS. One way is to use js templates. I'm a big fan of the hamlcoffeeassets library here: https://github.com/netzpirat/haml_coffee_assets Although it uses haml for the view, and not ERB. There are ERB variants as well.
You would add some markup to app/assets/templates/friend.jst.hamlc like so:
%p This is my friend markup #{#friend.name}
And then you can render it from your JS like this:
$('#friends').append(JST['templates/friend'](friend: {name: 'Bob'}))
Which will append the markup from your template with the values you've passed interpolated in. In my example you'd end up with this markup inside your #friends container:
<p>This is my friend markup Bob</p>
Alternatively you can render the partial you want via rails into your JSON response as just a string, and then insert that into your document...
So your JS might look something like this:
socket.onmessage = (m)=>
console.log("Recieved: #{m.data}")
msg = m.data.JSON.parse
switch msg.action
when "ret_init"
when "friend_udt"
refreshFriend(msg.friendHTML)
refreshFriend(html) ->
$('#friends').html(html)
UPDATE
In reference to your ERB question... First of all your partial is incredibly inefficient making similar calls to the database four times every time you render it. haml_coffee_assets is for use with the haml markup language (which I prefer over ERB), if you want ERB then use eco instead: https://github.com/sstephenson/eco
If you want to render this in the JS, then you need to send this "friend relation" data as JSON through the notification data response, you do not have access to active record OR any controller methods or instance variables when rendering javascript partials - they don't hit back to the server, they only use what is accessible by your javascript at the time.
This should really go to app/assets/javascripts/cp.js.coffee.erb, you can use erb in the asset pipeline just fine (see here) Make sure you are spelling the coffee extension right, though!
Doing this, you should be able to call this via ajax without problems, the path would be /assets/cp.js.
try this gem: 'coffeebeans'
name your coffee file as "some_file.html.erb"
<%= coffeescript_tag_do %>
# your coffee script here ...
<% end %>
in another erb file:
<%= render file: '.../some_file' %>

Saving ids in the cookies and passing them to ruby

I am using will_paginate in order to list huge number of files. I also have a check_box in order to choose files for the futher analysis.
To save the ids in the cookie while changing the pages I used following javascript:
<script src="/assets/jquery.cookie.js" type="text/javascript"></script>
<script type="text/javascript">
var checkedIds = []
$('.checkmeplease').on("change", function(){
if($(this).is(':checked')) {
checkedIds.push($(this).val())
}
else {
checkedIds.splice(checkedIds.indexOf($(this).val()), 1);
}
$.cookie('checked_file_ids', checkedIds,{path:'/'});
});
</script>
My checkboxes:
<% #files.each do |file| %>
<p><td> <%= check_box_tag "files[]", file.id,false,:class=>'checkmeplease' %></td> <%= file.name %></p>
<%end%>
It saves the IDs but when I change the page with will_pagination, the saved IDs disappear.
I do not load the previously saved IDs from the cookie. I have found little information about how to pass a javascript variable to ruby or how to catch a $.cookie('checkedIds') in the ruby.
How is it possible to do?
Thanks a lot.
You can't pass Javascript variable to Ruby or anything else for that matter.
You can, in this particular case, access on server (ruby) side the "checkedIds" cookie value that you've previously set using Javascript on client side. In Rails that would be as easy as cookies[:checkedIds]
On ruby side, use the value of the cookie to generate content of your choosing.

Passing a variable value from javascript to JSP

I have the following scenario
<select name="dropdown_Source" onchange="call()">
<% for (int i=0 ; i < a1.length; i++) { if (a1[i]==n ull) break; %>
<option value="<%=a1[i]%>">
<%=a1[i]%>
</option>
<% } %>
</select>
<script>
function call() {
var source = document.forms[0].dropdown_source.value;
// Now this 'source' value i have to pass to jsp function
<%
Admin a = new Admin(); //this is class defined
a.getResult(source); //but source is not resolved here
%>
}
</script>
How this source value should I pass in JSP function?
a.getResult() - function will return me list of dropdown elements and that list
I have to populate in another <option> tag.
You cannot do that. JavaScript executes on the client side after JSP page is already compiled and sent to the browser as response.
You can not mix javascript and java code. when you do
<%
Admin a = new Admin(); //this is class defined
a.getResult(source); //but source is not resolved here
%>
This means that code snippet will be processed at server side as this is plain java code.Now variable "source" is not java variable but a javascript variable which will come into picture when your html page loads on browser. So its a compilation error.
The best thing to do here is, once the javascript executes, take that source value and make an AJAX call to your server, process it and send the values back to the client and then populate your dropdown.

How do I make a ruby variable accessible to a javascript file?

I have two variables, <%= #user.lat %> and <%= #user.lng %>
These variables change depending on the user whose logged into my system - it's the address the user gave when registering with my app.
In a scripts.js file I've been trying to define them, so my Google map can show with the user's latitude and longitude.
But
function initialize_google_maps() {
var currentlatlng = new google.maps.LatLng(<%= #user.lat %>, <%= #user.lng %>);
etc, etc doesn't work, because it can't understand my ruby code.
I tried defining them at the top of the scripts.js file like:
var map_latitude = "<%= #user.lat %>";
var map_longitude = "<%= #user.lng %>";
and then using:
function initialize_google_maps() {
var currentlatlng = new google.maps.LatLng(map_latitude, map_longitude);
but I've learnt that you just can't put ruby in a js file. I did try renaming it to scripts.js.erb but that didn't work either.
So, how can I define <%= #user.lat %> and <%= #user.lng %> so they'll be recognised by my scripts.js file, and show up in my maps? I did try this answer here, creating a partial, but it didn't work for me. Maybe I was doing it wrong.
Please note: I can't simply put the code and maps function between script tags in a html.erb file because I'm using some ajax, and things get messed up - the ruby variables need to be recognised by the js file. Thanks.
It's possible to use Ruby in JavaScript file, but it's not recommended so I will not explain how.
To answer your question, you can just put the variable in your HTML attribute:
<div id="foo" data-lat="<%= #user.lat %>">Books are coming soon!</div>
And then extract it with JavaScript:
var lat = $("#foo").data("lat");
http://railscasts.com/episodes/324-passing-data-to-javascript will get you going in the right direction.
I think unobtrusive javascript is probably a good way to do this:
http://railscasts.com/episodes/205-unobtrusive-javascript
As the others suggested, you should aim for unobtrusive javascript.
Yet, you might want to use embedded javascript code in a js response for a view, for example. In this cases, you should use the erb extension in your javascript files, so the correct is.js.erb.

Can server side loop be done in javascript/ajax?

How can I loop server side code on the client without javascript? I have this loop in my rails app
//partial = _manufacturers
<div id="all_manufcaturers">
<% for manufacturers in #manufacturerss%>
ID: <%= h manufacturers.id %>
<% end %>
</div>
How can I render this using ajax? I know something like the following works since it is just a static replacement:
$("#manufacturers_count").html('Manufacturer - <%= #car.manufacturers.count %>');
But pseudocode like this does not work since the partial contains a loop:
$("#all_manufacturers").html('...render(manufacturers)...');
Yes, it can be done. You will want to make a server side script (e.g php) that builds a dataset for you and echos it with json_encode. You will then want to parse the response from the request with the appropriate javascript decode function in whatever library you're using (example, jQuery.decodeJSON()). You can then loop through the response set and render.

Categories

Resources