In my RoR project I got html page, where I changing div's background image with javascript. Javascript function send me index, and I want to use this index for getting element of ruby array.
Look into my code
function drawNewProject (index){
console.log(<%= 'index' %>)
<% index = 'index' %>
<% #existProjects = Admin::Project.order('weight') %>
<% #existProject = #existProjects[index] %>
var image = document.getElementById('block_one')
image.style.backgroundImage="url('<%= #existProject.image(:large) %>')";
}
But this line
<% #existProject = #existProjects[index] %>
Gives me error
no implicit conversion of String into Integer
Do you know how to do it correct? Thnx.
You have to think that the <%= erb %> block is executed in the server before being sent to the browser, and once there, the javascript is run.
Your browser has no idea about ruby or php or whatever... it just receives the html and the js (regardless is a static file, or a dynamically generated bunch of js) and runs it.
That means that all the data must be known at rendering time. If your application depends on dynamic data, or on your user interaction, then you have to do an ajax request and deliver back a call with the right js to be run by the browser.
Related
Action: a javascript action attempting to retrieve data based on two parameters, a user-input one and an issuing page parameter.
whereas in the past something like the following would work:
<%= javascript_tag do %> chart.data = data_<%=j params[:nation_id] %>; <% end %>
now with the javascript being 'packed', the compilation of syntax like <%=j params[:nation_id] %> does not work and returns :
/search.json?nation_id=%22%3C%=j%20params[:nation_id]%20%%3E%22&q=mi
modifying the packs/muni.js file as follows, also does not generate a proper url for the search function
var options = {
url: function(phrase) {
return '/search.json?nation_id="#{params[:nation_id]}"&q=' + phrase;
},
getValue: "name",
};
returning
/search.json?nation_id=%22
the page is set with /new?top%5Bnation_id%5D=1&commit=Set
How does the javascript pack need to be written?
Javascript pack is not rendered for each request/visitor - whole point is that it is packed once per deploy and is the same for all (except for when you have several packs, dynamic module loading and other advanced techniques, but still code is not changed per request). In fact, older method with asset pipeline is very similar in this aspect.
Do not try using ruby inside the pack, but instead think of a way to pass the parameter to the js code.
For example, you can pass it via a adding some html tag an querying it from javascript:
In view:
<meta name="nation_id" content="<%= params[:nation_id] %>" />
in js:
nation_id = document.querySelector('meta[name="nation_id"]').content;
return `/search.json?nation_id=${nation_id}&q=${phrase}`;
PS. also you might need to escape your phrase with encodeURIComponent
First let me tell you that I've searched for this and didn't manage to find any answer for my problem.
I have a lot of Javascript on my layouts/application.html.haml file:
### at the end of application.html.haml file
- if #instance_variable.condition
:javascript
// a lot js/jQuery code
:javascript
// more js code that uses #{ #instance.vars }
- if #another_condition.using.ruby.cody
:javascript
// more js code that uses #{ #instance.vars }
And I'm using instance vars within this code, which means that this vars will only be declared on the controller (application controller). As this is the application layout, these scripts run on every page of my website (and that's what I need of course).
What I want is to move all this code to a js.erb file (or .haml if possible). First - because is easier to manage this code in a separate file; Second - because I don't want to have <script> // a lot of js code </script> tags at the end of every html file, I want to have a <script async src='link'/> tag only.
Also I'm including already the application.coffee at the beginning of the file, but I need this script tag at the end of the html files.
I wouldn't recommend using partials for this. Because, your code uses variables, this means it changes depending on your variables. If you put them into a separate javascript file, the browser wouldn't know about the changes and use a cached file. A workaround would be to add some string (that changes when vars change) at the end of your filename, but then, you would lose all the benefits of moving your javascript into separate files.
A better way would be to define variables in your application.html.haml, move out your javascript code into separate files and just use defined variables.
application.html.haml
- if #instance_variable.condition
%script(src="path/to/my/script.js")
:javascript
= var some_var = #{#instance.vars}
%script(src="path/to/my/second_script_that_uses_var.js")
Thank you for your answer Uzbekjon, but after some research I found a way to do exactly what I wanted :)
In my 'layouts/application.html.haml' file, I added a script tag:
### at the end of application.html.haml file
%script{async: 'async', src: application_scripts_path}
Then I added this path to routes:
get 'application_scripts' => 'controller#application_scripts', as: :application_scripts
Then I just had to set this action application_scriptson my controller and create a new view (app/views/controller/application_scrips.js.erb):
class Controller < ActionController::Base
# 1
protect_from_forgery except: :application_scripts
def application_scripts
# 2
if condition.that.tells.me.this.request.is.valid
# 3
render formats: [:js] and return
end
render plain: ''
end
These steps were of course the harder ones to find out:
1 - I had to disable this protection, or else I would get this error:
ActionController::InvalidCrossOriginRequest at /application_scripts
Security warning: an embedded tag on another site requested protected JavaScript. If you know what you're doing, go ahead and disable forgery protection on this action to permit cross-origin JavaScript embedding.
2 - To make sure that no other site can request this script file (not that it could be a problem for me, but I preferred this way) I added a condition that makes sure the request comes from my website. In this case I was just checking if a user as logged in.
3 - The formats: [:js] tells Rails that the view is not .html, instead it's a .js file 'application_scripts.js.erb'
Finally I just had to move all my code from the application.html.haml file to the view file 'application_scripts.js.erb' and convert from haml code to erb as well.
<% #instance_variable.condition %>
// a lot js/jQuery code
// more js code that uses <%= #instance.vars %>
<% #another_condition.using.ruby.cody %>
// more js code that uses <%= #instance.vars %>
<% end %>
<% end %>
I want to start using websockets. I read all the docs and understand everything, but it leaves out something I need: How to pass information from view to JS?
I need to pass data from javascript to my controller. What I do not understand is, how do I get dynamically generated data in my view to the javascript to be sent?
Right now my view receives an instance variable on every HTTP request, it loops over every instance variable and makes a button which submits a hash with information extracted from that instance variable. I do not understand how to do the same thing with Javascript because Javascript will not understand Ruby classes.
This is what my code looks like now:
View/dashboards/_other_characters.html.erb
<% other_characters.each do |other_character| %>
<p><%= other_character.name %> is standing here (<%= other_character.power_level %>)</p>
<%= button_to "punch #{other_character.name}",
attacks_path(
target_type: other_character.class,
attack_type: :punch,
target_id: other_character,
target_name: other_character.name
) %>
<% end %>
This is what I would like to be able to do using JS
var task = {
name: 'Start taking advantage of WebSockets',
completed: false
}
var dispatcher = new WebSocketRails('localhost:3000/websocket');
dispatcher.trigger('tasks.create', task);
Try
<%= button_to "punch #{other_character.name}",
attacks_path(
target_type: other_character.class,
attack_type: :punch,
target_id: other_character,
target_name: other_character.name
), {id: '***', data: {name: '***', other_key: 'other_value'} } %>
Then you can access the data via jQuery data api.
When you need get dynamic data from view by client js, add data-attrs in your view dom then read it from dom API or other 3rd party js API.
In order to pass information from ruby to javascript you can use this gem: Gon, basically it transforms ruby variables and make them available to javascript on each view, take a look:
http://railscasts.com/episodes/324-passing-data-to-javascript
for any other alternative to achieve your purpose visit: https://www.ruby-toolbox.com/categories/javascript_tools#paloma
I have a js.erb template with the following code:
var latlng = new google.maps.LatLng(<%= session[:lat] %>, <%= session[:lng] %>);
I'm now trying to do the opposite (insert javascript into ruby):
<% session[:lat] = javascript_tag("document.write(location.lat());") %>
I think you're missing the point of Javascript.
Ruby code (<% .. %> parts in your examples) is run on the server.
Javascript code (var latlng = new google.maps.LatLng(10, 20); and document.write(location.lat());) is executed in the browser.
It's also executed after ruby code, when server has processed request and generated result page already.
If you want to know value of location.lat() on the server, you'll have to send it from the browser to the server in AJAX request. Any popular Javascript library will help with that.
Maybe you could try <%= raw [ruby/rails code] %>
This link may help: http://groups.google.com/group/rubyonrails-talk/browse_thread/thread/a160d9c2e55cfe36
I have this Javascript view in my Rails 3 project:
app/views/expenses/new_daily.js.erb
var i = parseInt($('#daily').attr('data-num')) + 1;
//$('#daily').append('agrego fila ' + i + ' <br />');
$('#daily').append('<%= escape_javascript(render(partial: 'new_expense', locals: { i: i })) %>');
$('#daily').attr('data-num', i);
I want to pass my 'i' javascript variable to a ruby partial through locals, How I can accomplish this?
As far as i know there is no way to do it directly and the reason is fairly simple too, html is executed at the server side and javascript is a client side language which means its executed in your local browser, thats why if you even try to pass a variable between the two you'll have to make a request to the server,
However this problem is tackled by calling an AJAX request, this AJAX request does the same thing as sending a new request to the server however it does that without refreshing or reloading the page to it gives the users the illusion that no request was made.
a guy asks a similar question Here
and you can learn more about AJAX Here on MDN:
Yes you can pass the value by using jquery;
<%=f.text_field :email ,:id=>"email_field" %>
<script type="text/javascript">
var my_email= "my#email.com"
$(document).ready(function(){
$("#email_field").val(my_email);
});
</script>
Simple answer is you can't. Partials are expanded at server side, and JavaScript variables are set later at client side. You could make i (as a variable name) a parameter of the partial and use it there.
render :partial => 'xx', :locals => { :variable => 'i' }
And in partial
alert(<%= variable %>);
Check out the gon gem. https://github.com/gazay/gon
It gives you a simple object you can pass variables to that will be available to your scripts via window.gon
Also referenced here
http://railscasts.com/episodes/324-passing-data-to-javascript
1) You may create a js tag with global variable in you erb template, after that you will be able to access that variable from any js file
<%= javascript_tag do %>
window.productsURL = '<%= j products_url %>';
<% end %>
2) You can pass data to data-attribute in erb template and access it by js on client side that way $('#products').data('products')
<%= content_tag "div", id: "products", data: {products: Product.limit(10)} do %>
Loading products...
<% end %>
3) You can use gon, to use your Rails variables in your js
There is a good article, read it and fine solution for your specific case
http://railscasts.com/episodes/324-passing-data-to-javascript,
more comments are here http://railscasts.com/episodes/324-passing-data-to-javascript?view=asciicast
Here's a few different options on how to do it:
http://jing.io/t/pass-javascript-variables-to-rails-controller.html
The best other answers here are right that this can't be done by passing the javascript variable into an erb partial, since it is rendered on the server, not the client.
But since anyone looking for this is probably interested in a work-around solution, which I don't see here, I will post this example that works well with Rails UJS and Turbolinks.
First, you set up your controller to return a partial as HTML:
format.html { render partial: "new_expense" }
Next, write a javascript AJAX function in app/views/expenses/new_daily.js.erb:
var i = parseInt($('#daily').attr('data-num')) + 1;
$.ajax({
url: '/daily',
type: 'GET',
dataType: 'html',
contentType: "application/html",
success: function(response) {
$('#daily').replaceWith(response)
$('#daily').attr('data-num', i);
}
});
This is going to get your Rails partial as an html fragment that you can use to replace that part of your rendered page. You can use jQuery to get your data-num attribute value, do some math on it, replace the partial in your view, and then set the attribute value again.
You may ask why go to all the trouble of getting the Rails partial and replace it on the page, instead of just getting the data attribute, doing math on it, and setting that? The answer is that this is the best, and perhaps the only way of doing something which is really essential when rendering a Rails partial using UJS while handling an asynchronous response to an action.
If you are handling an asynchronous response from your server in a create.js.erb template, then your variables (#daily, for example) are not going to reflect the work done after the request has completed (for example, if there has been processing on a background server like Sidekiq). In that case you don't have up-to-date action response variables to pass into your Rails partial in the js.erb file, but you also can't pass the javascript data response into your partial, as pointed out in this question.
As far as I know, this approach is the only way to get a fully up-to-date partial after receiving a response to an asynchronous response (not shown). This get you the up-to-date partial, allows you to get your javascript into it, and is flexible enough to work in pretty much any use case.
Let's make shure we understand each other. Your erb template (new_daily.js.erb) will be processed on the server side, ruby code will be evaluated (within <% %>), substitution made, and then resulting javascript will be sent to browser. On the client side the browser will then evaluate this javascript code and variable i will be assigned a value.
Now when do you want to pass this variable and to what partial?