How to Render JS and Iterate Over Array With Rails Controller - javascript

I have a button on a view that triggers a controller action, which runs a bunch of stuff and returns and array of strings (each string is formatted as a div ex; "Hello"). I then want to take this array and add each element to the page on which the button was clicked.
Controller Method:
def test
#id = params[:id]
if #id == 'run'
#res = Preflight.run
respond_to do |format|
format.js {render :js => 'run'}
end
else
render #id
end
end
run.js.erb File:
$('#header3').show();
$('#header2').hide();
<%= puts 'made it to the js file' %>
<% #res.each do |line| %>
$('#results').append(<%= line %>);
<% end %>
I know that #res is returning the array as intended, I'm unable to get the JS to trigger. Any ideas? It doesn't run the show/hide so I think the bug has to do with how I'm attempting to call the js file, but I'm unsure what I'm doing wrong here.

Do you use the remote: true option in your HTML, when you call the test action?

Remember that when you want to output a JS string you need to wrap it in quotes:
$('#results').append("<%= #res.join() %>");

Related

How to Reference ruby code Inside a JS alert tag

I'm new to JS and was wondering if someone could help me figure this alert out?
<% if #candy.errors %>
<%= javascript_tag do %>
alert('<%= #candy.errors.full_messages %>')
<% end %>
<% end %>
This is all that comes up on the alert: []
<% if #candy.errors %> will always return a truthy value. The value it returns is an instance of ActiveModel::Errors. By truthy, I mean it will never return false or nil, and therefore your alert will always show...even if there are no errors with #candy.
You'll need to add .any? to return false if there are no errors.
<% if #candy.errors.any? %>
If my assumption that there are no errors with the #candy you are working with is correct, no alert should show when any? is added.
To manually add an error to #candy, add this line before <% if #candy.errors.any? %>...
<% #candy.errors.add :base, "Test" %>
If an alert pops up then the issue is simply that #candy has no errors and your call to #candy.errors.full_messages correctly returns an empty array.

Rails - how put javascript variable into erb code

I've seen some similar question, but still don't know how achieve my goal.
I want to do that thing:
Display modal with products represented by divs.
User choose some products (I add .active class to chosen products)
Then I use jQuery to make array of chosen products ids.
In the end I want to create div for each product, which will be include some informations about this product from database. I'm using js .append() to do it. And here is a problem.
This code is in my script tag in proper view.
var chosen_products_array;
$('.product-to-choose').click(function() {
$(this).toggleClass("active");
$(this).find('i').toggleClass("visible");
});
$('#chosen-products-confirm').click(function() {
var chosen_products = $('.product-to-choose.active');
chosen_products_array = jQuery.makeArray( chosen_products );
});
$('#confirm').click(function() {
var textToInsert = '<div><h4>Products:</h4>';
$.each(chosen_products_array, function(count, item) {
var id = $(item).attr('id').substr(8); // id is product_number
textToInsert += '<div><li name="chosen-product"> <%= current_user.products.find(' + id +').name %></li></div>';
});
textToInsert += '</div>';
$('#div-example').append(textToInsert);
});
My controller create action:
def create
#meal = current_user.meals.build(meal_params)
if #meal.save
current_user.type_tags.each do |type_tag|
key = "type#{type_tag.id}"
if params[key]
#meal.type_tags << type_tag # zapis do bazy danych
end
end
flash[:success] = "Create new meal!"
redirect_to meals_path
else
#render 'meals/new'
end
end
This line generates error:
textToInsert += '<div><li name="chosen-product"> <%= current_user.products.find(' + id +').name %></li></div>';
Error:
Couldn't find Product with 'id'=+id+ [WHERE "products"."user_id" = ?]
I know there is a problem in passing js variables to rails erb, but how can I solve it in this case? I tried with gon too.
In my controller, I added:
gon.products = current_user.products
and then try
alert(gon.products)
it's ok - array of objects, but when I try
alert(gon.products.find(1))
it doesn't work.
Have you got any idea how can I put this javascript id variable to erb code? Or maybe is any different solution?
Probably the best would be to add a remote form (it may be hidden) that posts whatever you want (javascript values) and then it is handled by a controller. Then you can render it with js views.
This would probably be the most "rails-like" solution.
Here's some code:
In the routes:
resource :my_form, only: :create
In the view:
<%= form_tag(my_form_path, remote: true, method: :post) do %>
<%= hidden_field_tag :val %>
<% end %>
You alter the val dynamically by javascript, and submit the form whenever you want to.
Then, in the controller you have something like this:
respond_to :js
def create
# do something with params['val']
#my_val = params['val']
end
And you would also add create.js.erb view, where you could add some javascript that can use any of the instance variables created in the controller.
//create.js.erb
$('#someElement').html('<%= #my_val %>');
Let me stress if it is not clear, the form is remote (ajax), so it is sent in the background and the page is not reloaded.
When the browser receives the response, it may contain any javascript you decide to render (the contents of create.js.erb), and then the browser executes that javascript.
So, you can add there any jquery commands with arguments that you changed dynamically by rails, or you could also render html partials and replace any elements with them, like this:
//create.js.erb
$('#my_id').html('<%= j(render partial: 'my_form/_some_partial.html.erb', locals: { my_val: #my_val }) %>');
More details on Working with JavaScript in Rails
UPDATE
Another, inferior but simpler to implement solution would be to always render all products, but have them hidden initially, and then show them by jQuery on demand. You would just need to add appropriate css classes or data attributes to those products, as well as the links you use to select them.
The problem is that erb code is evaluated on the server before the browser even fetches the javascript file, so it doesn't make sense to use this way. It's recommended that you only use erb in your javascript for simple things like asset_path
I think first make your model visible to the browser as js variable(json object) . Some thing like below at the end of your view file(below is the haml syntax):
:javascript
var userProducts = #{#current_user.products.to_json};
Then use it in javascript expression

Rails partials not picking up javascript format

I've added JavaScript partials many times before, but admittedly not for a while. The short of it is, I'm missing something stupid.
When I try to render partial 'deleteme.js' at the end of this view:
/app/views/projects/myview.html.slim:
h2 Stuff goes here
render partial: '/projects/thisworks' # Render html partial
render partial: '/projects/deleteme.js' # Render js partial...fails
Which renders this partial:
/app/views/projects/_deleteme.js.erb:
console.log("Oh FFS, Work");
I get:
ActionView::MissingTemplate in Projects#show
Showing
/Users/aj/Web/Rails/sh3/app/views/projects/show.html.slim
where line #5 raised:
Missing partial /projects/deleteme with {:locale=>[:en],
:formats=>[:html], :handlers=>[:erb, :builder, :slim, :jbuilder,
:coffee, :haml]}. Searched in: *
...
The incriminating bit is that it's searching for formats => [:html] only, but I thought appending .js automatically tells rails to search for javascript. If anyone has any ideas as to why it's not finding the JS template, I'd be really appreciative. Action code is a very basic:
def show
#project = Project.find(params[:id])
end
/app/views/projects/_deleteme.js.erb:
You are getting partial naming intertwined with Javascript action naming!
/app/views/projects/deleteme.js.erb:
rename your javascript file, remove the _
You have to make sure your show responds to js
def show
respond_to do |format|
format.js
format.html
end
end
You are calling a partial inside a slim template so it expects to find
app/views/projects/_deleteme.js.slim

Returning javascript from rails helper

I am having problems returning javascript from helper functions. I am unable to get the following test case to work:
function in helpers/application_helper.rb
def show_stuff
return '$("div#flash").html("<p> stuff </p>");'
end
now I try to call this helper function in general.js.erb
<%= show_stuff %>
Here is the output
$("div#flash").html("<p> stuff </p>");
I've also tried show_stuff.html_safe and raw show_stuff and had no luck. I feel the issue is Rails auto-escaping html but have been unable to find a solution.
ERB is escaping the characters in your outputted Javascript.
To prevent this happening use the raw method in your template.
<%= javascript_tag do %>
<%= raw(show_stuff) %>
<% end %>
I've added the javascript_tag method around this for context.

Passing objects from Rails RJS to a javascript function call without quoting the values?

In a Ruby on Rails project I need to have a JavaScript function executed at the end of an Ajax call. My problem is that the values being passed into the JavaScript function being called with page.call are being wrapped up in quotes. Not too much of a problem if you're passing in strings but one of the values is a string representation of a JavaScript Array, i.e. [0,1,2,3].
Here are what I feel are the important snippets of code.
I have an observe_field that watches a select drop down list.
<%= observe_field("project_select_list",
:loading => "Element.show('tree_indicator')",
:complete => "Element.hide('tree_indicator')",
:url => {:controller => "projects", :action => "change_project"},
:with => "id")
%>
In the project_controller
def change_project()
#current_project = Project.find(params[:id])
end
And in change_project.rjs
page.replace_html("project_name", #current_project.name)
page.visual_effect(:highlight, "project_name")
page.call("buildYUITreeView", "project_tree", #current_project.get_directory_contents(#current_project.local_path, 0))
The last value:
#current_project.get_directory_contents(#current_project.local_path, 0))
is what's causing me issues. I just want it to send the value, for example [0,1,2,3], but it's sending "[0,1,2,3]" which is causing the JS to blow up.
This partial does what it's supposed to in that it sends the data and not a string to the JavaScript code that gets put on the page.
<% javascript_tag do -%>
YAHOO.util.Event.addListener("dom:loaded", "load", buildYUITreeView("<%= tree_id %>", <%= project.get_directory_contents(project.local_path, 0) %>));
<% end -%>
With this in mind I'm playing around with using a partial and just rendering it to call the JS function when I need to but that seems like such a hack.
How can I make page.call not wrap the data sent as parameters in quotes, or how should I go about passing this data to the JS function for execution after the Ajax call is complete?
Tom was on the right track, the << method is the way to go because it will insert any javascript directly. You'll want to use that instead of call.
page << "buildUYITreeView('project_tree', #{#current_project.get_directory_contents(#current_project.local_path, 0))})"
You can do the same thing with the YAHOO line as tom showed which should be more efficient than using a partial with a javascript tag.
You could use the << method instead to emit raw javascript:
page << 'YAHOO.util.Event.addListener("dom:loaded", "load", buildYUITreeView("project_tree", '+#current_project.get_directory_contents(#current_project.local_path, 0)+'))'

Categories