I got a situation, there is a Javascript variable I need pass to rails partial view.
For example in test.html.erb
<script type="text/javascript">
var array = <%= raw sort_section %>
for(i = 0; i < array.length; i++) {
$('#test').append("<%= j render :partial => 'section_in_panel', :locals => {:section => raw array[i]} %>");
}
</script>
But it keep throwing syntax error, I have try many ways like
{:section => j sort_section_js[i]} %>"
{:section =>" + sort_section_js[i] + "}%>"
I need to use that because I want to call ajax to change array dynamically.
Update
So, maybe I need to write a controller
def get_new_variable
...
return new_variable
end
Then in the test.html.erb
<script>
$('test').onclick(function(event) {
//write some ajax call
//get new_variable
$('#test').empty();
$('#test').append("<%= j render :partial => 'section_in_panel', :locals => {:section => raw new_variable} %>");
});
)</script>
Is that right direction?
As Alberto Juan wrote in comment, you can't use javascript variable in ruby code.
Ruby code will be interpreted before javascript and will not know what is the i.
Update: Your update will not work either as your using new_variable you get in your javascript code.
For using partial after ajax call, follow instructions in this link
Example:
items/index.html.erb
<div class="grid">
<% #categories.each do |cat| %>
<%= link_to cat.name, fetch_items_path(:cat_id => cat.id), :remote => true %>
<% end %>
<%= render partial: 'item_grid', locals: { items: #items} %>
</div>
routes.rb
get "/fetch_items" => 'items#from_category', as: 'fetch_items'
items_controller.rb
def index
#items = Item.all
#categories = Category.all
end
def from_category
#selected = Item.where(:category_id => params[:cat_id])
respond_to do |format|
format.js
end
end
views/items/from_category.js.erb
$("#items_grid").html("<%= escape_javascript(render partial: 'items_list', locals: { items: #selected } ) %>");
You can use gem gon or simply do something like this:
<script>
MyVars[:someVar] = <%= some_value %>;
</script>
But, I recommend you to separate your backend an frontend code and use JSON for passing data to JS.
Related
In my Rails 7 (with bootstrap) app I need to create a table with all users transaction that has on each row an arrow that when clicked on, expands that row inside which is a new table (that's what I think it is - a new table). I think the attached design will better explain what I mean:
To achieved that I could try javascript with something like this https://jsfiddle.net/Wfxpu/180/ but I'm not sure if it's a modern approach. I'm wondering is it possible to a write something like this without any JS code using turbo maybe? or even pure HTML ?
Here is what I was trying to do:
# transaction controller
class TransactionsController < ApplicationController
def index
response = client.transactions.list(platform_id: current_user.platform_id, page: 1, per_page: 100)
#transactions = response.body['data']
end
private
def client
#client ||= TestAPI::Client.new
end
end
so then sample table would be:
# views/transactions/index
<table>
<% #transactions.each do |transaction| %>
<tr><%= transaction.amount %></tr>
<% end %>
</table>
You could try using a remote link_to as your "arrow" to invoke show_more action.
<%= link_to your_path, remote: true do %>
your image
<% end %>
In your controller you would need to respond to that with
def show_more
...
#data_to_show = some_database_call
respond_to do |format|
format.js
...
end
end
then in show_more.js.erb you can run javascript using the data that you just received.
var content = document.querySelector("#hidden-section-1");
content.innerHTML = ""
content.insertAdjacentHTML("beforeend",
"<%= j render('layouts/your_template', data: #data_to_show) %>");
where layouts/your_template would be a template with all the stuff you want to show(the "other" table you mentioned)
<h1> merchant: <%= data.merchant %> <h1>
...
<p> transaction_id: <%= data.transaction_id %> </p>
...
I created a file inside my javascript folder "load-contacts.js" in hopes of trying to load the collections as well as the pagination via jquery.
$(document).on('turbolinks:load', function() {
$('#contacts').html("<%= j render(#contacts) %>");
$('#paginator').html("<%= j paginate #contacts, remote: true %>");
});
When I run this code it actually works and change the part where it intended to change. However, it is only rendering it as text as it instead of the collection and the pagination (kaminari gem).
Here's how it looks like:
Any idea what am i missing here?
UPDATES:
Here's my contacts controller
class ContactsController < ApplicationController
before_action :find_params, only: [:edit, :update, :destroy]
def index
# catch the group id from params in session
session[:selected_group_id] = params[:group_id]
#contacts = Contact.by_group(params[:group_id]).search(params[:term]).order(created_at: :desc).page params[:page]
end
def autocomplete
#contacts = Contact.search(params[:term]).order(created_at: :desc).page(params[:page])
render json: #contacts.map { |contact| { id: contact.id, value: contact.name } }
end
def new
#contact = Contact.new
end
def create
#contact = Contact.new(contact_params)
if #contact.save
flash[:success] = "Contact was successfully created."
redirect_to(previous_query_string)
else
render 'new'
end
end
def edit
end
def update
if #contact.update(contact_params)
flash[:success] = "Contact successfully updated."
redirect_to(previous_query_string)
else
render 'edit'
end
end
def destroy
#contact.destroy
flash[:success] = "Contact successfuly deleted."
redirect_to contacts_path
end
private
def contact_params
params.require(:contact).permit(:name, :email, :phone, :mobile, :company, :address, :city, :state, :country, :zip, :group_id, :avatar)
end
def find_params
#contact = Contact.find(params[:id])
end
def previous_query_string
session[:selected_group_id] ? { group_id: session[:selected_group_id] } : {}
end
end
Here's the part for the kaminari gem pagination:
<div class="card-footer">
<div class="pagination justify-content-center" id="paginator">
<%= paginate #contacts, remote: true %>
</div>
</div>
And here's where I am suppose to be rendering the contacts inside the views/contacts/index.html.erb:
<table class="table" id="contacts">
<%= render partial: "contact", object: #contacts, remote: true %>
</table>
you can't use j render outside .erb. Because j render is method of rails, your js just know it is string
what you need are use script tag inside your html.erb, or use rails ajax. It is working as expected
reference: How to render partial on the same page after clicking on link_to with AJAX
have you tried escape_javascript before calling render.
something like:
<%= escape_javascript render(my_partial) %>
I'm trying to append new comments to a list of existing comments using javascript and ajax. I set up my Comments#create to create a new comment and then render its text. But how can I access this text with ajax?
controllers/comments_controller.rb
def new
#comment = Comment.new
#comments = Comment.all
end
def create
#thing = Thing.find(params[:thing_id])
#comment = #thing.comments.create(comment_params)
render text: #comment.text.to_s + "".html_safe
end
My form for a new comment and ajax/javascript attempt:
<%= form_for([#thing, #comment], remote: true) do |f| %>
<%= f.text_area :text, :placeholder => "Explain your rating..." %>
<div id="btn"><%= f.submit "Post", class: "btn", id: "postacomment" %></div>
<script type="text/javascript">
$("#postacomment").click(function() {
$.get( "<%= new_thing_comment_path(:id => #comment.id) %>", function( data ) {
$('#comments_h2').prepend( data );
});
});
</script>
<% end %>
First of all, don't try to bend HTTP methods to fill your needs, follow them instead.
If you want to respond to javascript with rails, that is fairly easy. On your comments controller:
def new
#comment = Comment.new
#comments = Comment.all
end
def create
#thing = Thing.find(params[:thing_id])
#comment = #thing.comments.create(comment_params)
respond_to do |format|
format.html { redirect_to new_comments_path } #this is just a redirection in case JS is disabled
format.js
end
end
As you can see we are now responding to two types of formats, in this case html and js, this forces you to have those corresponding views, or at least for the js version which may look like this:
app/views/comments/create.js.erb:
$('#comments_h2').prepend("<%= j #comment %>");
In the example above I'm assuming you have a partial for rendering a comment, it should look something like:
app/views/comments/_comment.html.erb:
<h2><%= comment.content %></h2>
Obviously you have to update that file to meet your needs.
Hope it helps!
I have a comment model that posts under a micropost model and they are both on the same page. The problem that I have is that when the comments paginate under the micropost the links lead to the second page of the microposts rather than the second page of comments but instead of redirecting to the second page I would like to render more comments that are paginated through ajax but I am confused with how to get to the nested route for this. Anyone have any suggestions for this? The routes part is getting to me. Here are the code for my micropost/comment section HTML. Also where do I have to insert the respond_to do section in which controller? Thank you!
Micropost/Comment Section HTML
<div id='CommentContainer-<%= micropost.id%>' class='CommentContainer Condensed2'>
<div class='Comment'>
<%= render :partial => "comments/form", :locals => { :micropost => micropost } %>
</div>
<div id='comments'>
<% comments = micropost.comments.paginate(:per_page => 5, :page => params[:page]) %>
<%= render comments %>
<%= will_paginate comments, :class =>"pagination" %>
</div>
</div>
User Controller - The page it is shown on
class UsersController < ApplicationController
def show
#user = User.find(params[:id])
#school = School.find(params[:id])
#comment = Comment.find(params[:id])
#micropost = Micropost.new
#comment = Comment.new
#comment = #micropost.comments.build(params[:comment])
#comments = #micropost.comments.paginate(:page => params[:page], :per_page => 5)
#microposts = #user.microposts.order('created_at DESC').paginate(:per_page => 10, :page => params[:page])
end
end
Most people go by the classic railscast on this:
http://asciicasts.com/episodes/174-pagination-with-ajax
Note that now, for rails 3 you just include it with
gem 'will_paginate'
- and bundle install of course. - instead of the longwinded
gem 'mislav-will_paginate', :lib => 'will_paginate', :source => 'http://gems.github.com'
I have a comment model that is paginated and I would like the comments to load more comments on the same page whenever the next button is clicked. I have somewhat of an idea of how to go about doing this but can anyone advise how to go about doing this. I have some code already.
For the comment section instead of render I think it may have to be looking for the micropost and its id to find the right comments to append but I am unsure about how to go about tying this all together.
Pagination JS
$(function() {
$("#CommentPagin a").live("click", function() {
$.getScript(this.href);
return false;
});
});
Show JS
$("#cc").append('<%= escape_javascript(render :partial => "users/comments" )%>');
Comment Section
<div id='comments'>
<% comments = micropost.comments.paginate(:per_page => 5, :page => params[:page]) %>
<div id="CommentPagin">
<span class="CommentArrowIcon"></span>
<%= will_paginate comments, :page_links => false , :class =>"pagination" %>
</div>
<%= render 'users/comments' %>
</div>
Comment Rendering Section
<div id="cc">
<% comments = micropost.comments.paginate(:per_page => 5, :page => params[:page]) %>
<%= render comments %>
</div>
User Controller
def show
#user = User.find(params[:id])
#school = School.find(params[:id])
#comment = Comment.find(params[:id])
#micropost = Micropost.new
#comment = Comment.new
#comment = #micropost.comments.build(params[:comment])
#microposts = #user.microposts.order('created_at DESC').paginate(:per_page => 10, :page => params[:page])
respond_to do |format|
format.html
format.js
end
end
I´m a bit rusty with rails so this is somewhat generic answer.
I would load the next n comments from a route / action that renders just your Comment Rendering Section as HTML
Just think of it as you where requesting assets from your own API and using them to update the page.
Pagination JS
/**
* jQuery 1.7+
* use .delegate() for older versions.
**/
$("#CommentPagin").on('click', 'a', function(e){
// Get data from server - make sure url has params for per_page and page.
$.get($(this).attr('href'), function(data){
// refresh client with data
$("#cc").append(data);
});
});