Iterate through array passed from controller - javascript

I'm using Ruby on Rails.
Here is my code for the view, where I make a post to the controller, passing parameter "tplangroup.id":
<div id="collapse">
<%= form_tag(tplans_collapse_tplans_path, :method => 'post', :remote => true ) do %>
<%= hidden_field_tag(:tplangroup_id, tplangroup.id) %>
<% end %>
</div>
Here is my code on the controller end, where it parses the necessary data and shoots back array "#ordered_tplans"
def collapse_tplans
#collapsed_tplangroup = Tplangroup.find(params[:tplangroup_id])
tplans_from_tplangroup = #collapsed_tplangroup.tplans
#ordered_tplans = tplans_from_tplangroup.order("favrank DESC")
return #ordered_tplans
end
Since I called :remote => true in the original form located in the view, it passes this array to a file called "collapse_tplans.js"
My question is: what is the best way/practice to parse through this array now passed to the js file, and display its contents in the view? Do I use rails code in the js file to manipulate the object? Or do I do it all in javascript/jquery? What is the best practice, and could you provide any example?
Thanks!

Really kind of depends on how you want to go about it, as with all code, there are many ways to skin a cat. I find the easiest way is to use the return ujs as an erb file (collapse_tplans.js.erb) and from there, choose the element on the page you want to attach the retuned object to, and call a standard erb or haml partial where your iterations can be done clearly.
e.g.
In collapse_tplans.js.erb
$('#my_wacky_element').append("<%= j render(:partial => 'collapse_tplans', :locals => { :ordered_tplans => #ordered_tplans }) %>");
Then in
_collapse_tplans.html.erb
<ul>
<%= ordered_tplans.each do |tplan| %>
<li><%= tplan.attribute %></li>

Here is a RailsCast on how to pass data to js from rails:
http://railscasts.com/episodes/324-passing-data-to-javascript?view=asciicast

Related

Locals issue in Rails application

I am getting errors while doing an AJAX call with remote: true with locals. Here's the error:
ActionView::Template::Error (undefined local variable or method `f' for #<#<Class:0x94db890>:0x9ab41d0>):
Here is my code below:
new.html.erb
<%= form_for(#author) do |f| %>
<div class="field">
<%= f.label :name %><br>
<%= f.text_field :name %>
</div>
<div class="field">
<%= f.label :age %><br>
<%= f.number_field :age %>
</div>
<%= link_to "Add Books" , remote: true %>
<div id = "add_book"></div>
<%= f.submit %>
Controller
def new
#author = Author.new
#books = #author.books.build
respond_to do |format|
format.html
format.js
end
end
new.js.erb
$("#add_book").append(" <%= escape_javascript(render partial: 'addbook', :locals => { :f => f }) %> ");
You are calling the new action of your controller using remote: true (an AJAX call). This will result in new.js.erb being rendered to be sent back as the response - the new.html.erb will not be processed.
Within new.js.erb you have:
$("#add_book").append(" <%= escape_javascript(render partial: 'addbook', :locals => { :f => f }) %> ");
Meaning it is attempting to render the addbook partial and set up a local variable for it, to be referenced in the partial as f, and assigning it the value (local to new.js.erb) f.
new.js.erb has not declared the local var f and thus your error.
To assist more we would need to know what the intention of this variable is - in what way does _addbook.html.erb require it?
So... the way that an erb template works is this:
Rails generates a page, in your example, this would be new by going through the new action in the controller and gathering up all the variables (eg author and books).
Then it gets the right template for the action. In the case when you first open up the new page you get the form... right? That comes from the new.html.erb template.
So rails reads through the template and runs the ruby code... replacing it with appropriate html. Then it sends the html to the browser.
By the time it's sent it to the browser, there is no longer any ruby code... just html, because the browser doesn't understand ruby, just html - so that's all that gets sent.
Now... the browser has an html form, that contains some js - this would be the add books link - it's html, that calls some js that sends a request to your rails app.
The rails app then goes through the new action, gathering the variables again, but this time, it doesn't render the html template... because it got called by js. So it grabs the js template instead.
At this point rails knows nothing about the html template. Anything that was in the html template is long gone - sent away to the browser. All it knows about is what is in the js template. It tries to run the ruby code in the template... and it's asking for f... and f doesn't exist in your js template... so it gets confused and tells you it doesn't know about this f thing.
It doesn't matter that at some point in the past it rendered a form called f, because that belonged to a way distant past request that no longer exists. The browser doesn't tell rails about f because it never knew about it (that was part of the ruby, not the html that is all that the browser ever saw). So... there is no f. ;)
In this case - I am not sure you need to pass f in as a local variable at all. If you are rendering the template that contains the form... then you don't need to pass in a form because it will already be rendering the form. Try just rendering the partial without passing in locals, and see what happens... if you get a bug, we can then work on that.

Rails 4 - event to run code after a partial is rendered

I have a js.erb file that is called with ajax through a controller action. The js.erb file renders a partial. Inside the partial is a data attribute that is generated based from the model. I need a way to run code only after the partial is rendered because the code is using information in the data attribute.
items_controller.rb
def remove_tag
#item = Item.find_by_id(params[:id])
//code to remove tag from item
#item.save
respond_to do |format|
format.js
#item.reload
end
end
remove_tag.js.erb
$("#taglist").html('<%= escape_javascript(render partial: "items/tag_list", locals: {item: #item}) %>');
//the code below needs to be run after the above partial is rendered
$('#add-tag').rules("add", {
tagUniqueness: $('#taglist').data('tag-list').split(', ')
});
_tag_list.html.erb
<div id="taglist" data-tag-list="<%= item.all_tags_list %>">
//more html
</div>
The way it is now, the .rules method is using html data that was there before the partial updates it.
This type of functionality would lend itself to callbacks in javascript/jquery...
A callback function is executed after the current effect is 100% finished.
We used callbacks for executing functions after ajax loads (which had to remain asynchronous). They are highly effective if you can get them to work.
There's a great reference here:
$("#taglist").html('<%= escape_javascript(render partial: "items/tag_list", locals: {item: #item}) %>').promise().done(function(){
$('#add-tag').rules("add", {
tagUniqueness: <%= js #badge.all_tags_list.to_json %>
});
});
To convert hashes or arrays from Ruby to javascript you can use .to_json as JSON basically is a subset of javascript.
$('#add-tag').rules("add", {
tagUniqueness: <%= js #badge.all_tags_list.to_json %>
});

Rails 3 make ajax using jquery and execute .js.erb

I have the following haml code:
%input{:value => "", :type => "button",:class => "SendBtn", :onclick => "$.get('#{send_path}',{parameter:$('#parameter').val()}); "}
This input executes an event in the controller.
// This is my controller
def send
if request.xhr?
// do stuff
end
end
But my js code in the corresponding .js.erb file is not being executed. It is returned as the response of the get request.
// send.js.erb
alert('hello');
How is the rails way to have this code executed?
Your problem is not Rails related, it's jQuery. With the get method you are just fetching more or less plain text. This will not get executed. You could do an eval on the text but there is a better way. Use the getScript method from jQuery. This will fetch and execute your code.
As a side note, there are two things that are bothering me in your code:
You are using inline JavaScript. try to remove this by using a data- attribute for your send path, like this data: { sendPath: send_path }, and retrieving it with $(yourInput).data('sendPath') in your application.js file.
From my personal view I do not like to put executing JavaScript code in ERB templates. I find that this fragments the front end logic of my app. For me it worked better to put the logic in .js files and communicate with the server over JSON.
As #topek said, you have to use $.getScript. Also in your situation better approach is to use button_to with :remote => true property instead of plain input.
<%= button_to "Do Something",
{ :controller => :somecontroller, :action=> :something },
{ :remote => true }
%>
Also you can pass attributes to button_to (but you have add parameter to your route definition).
<%= button_to "Do Something",
{ :controller => :somecontroller, :action=> :something, :param => #object.id },
{ :remote => true } %>
Here goes documentation for button_to: http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-button_to

How to get an argument for link_to dynamically from the site rails 3

I am using a the link_to method in Rails the unobstrusive jQuery way:
<%= link_to "save",
update_elements_diagram_path(diagram, :shown_elements => ["speed", "position_break"]),
:method => :post, :remote => true, :class => "close",
:onclick => "stringViewsTableLoading()" %>
This works. But now I want to get the arguments "shown_elements" dynamically from the users inputs.
I know how to get them from the form to javascript, but how from javascript to Rails?
... shown_elements => "getShownElements()"
or something similar would be great.
Greetings
Sandro
Not sure I see what you mean there, so I guess that you somehow have a few fields on your page, and that what you want is to get the value of those fields in the :shown_elements.
This is not how it's supposed to be done. Think the other way around. You are posting a form using :method => :post, which means that those will be accessible in your target controller using params[].
def DiagramsController < ApplicationController
def update_elements
shown_elements = params[:shown_elements] # or something like this.
end
end
Hope this helps!

Missing template after link_to_remote

I'm using link_to_remote to update a partial on my page. The problem is that Rails isn't finding my partial.
I am specifying the full path to my partial(an html.erb file) in the controller method:
def my_method
create something
render :partial => '/shared/partials/my_partial_form', :layout => 'false'
end
I know the controller method is getting hit, since "something" gets created. I get the error "Template missing [:controller_name]/[:method_name].js.erb not found".
Can anyone explain why Rails appears to be using a default path to a js.erb?
Thanks in advance!
Rails is responding to the JS format. render :partial doesn't count as the action's 1 render/redirect call per action. Without a proper render or redirect call, Rails will call render with default arguments based on the format, controller and action.
Render :partial just returns text to the caller, it does not build a response. In this case the partial is rendered into HTML, but then nothing is done with it. P.S. :layout => false option is superfluous when rendering a partial.
You want to use render :update or RJS files to do the same through a template.
Assuming you want to replace the entire web page, the short version is do something like this:
def my_method create something
render :update do |page|
page.replace_html :body, :partial => '/shared/partials/my_partial_form'
end
end
Going the RJS route you could create the app/views/resource/my_method.rjs file and fill it with
page.replace_html :body, :partial => '/shared/partials/my_partial_form'
Try removing the / in front of shared.
render :partial => 'shared/partials/my_partial_form', :layout => 'false'

Categories

Resources