Rails: Render pages of Will_Paginate through Ajax/jQuery - javascript

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'

Related

Rails jQuery is rendering text instead of collection

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) %>

How to pass javascript variable to rails partial view

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.

Remote: true with link_to with params

I have following problem
I have link_to
//_sort_by.html.erb
<%= link_to "sort", :sort_by => "things", remote: true %>
And in my controller I have function which choose posts according to sort_by
def show_posts
#category=Category.find_by(name: params[:sort_by])
if(#category)
#posts=Post.where(category_id: #category)
respond_to do |format|
format.js
format.html
end
else
#posts=Post.all
end
end
and in views
//show_posts.html.erb
<div class="posts">
<%= render #posts %>
</div>
//
and I have _post.html.erb
It works fine (obviously without remote: true), but it refreshes site everytime when I change category of posts so
in show_posts.js.erb I'd like to refresh only class="posts", like
$('.posts').load(location.href + " .posts");
In routes.rb I have get 'show_posts'. But unfortunatelly it doesn't work. Could someone help me?
Edit:
changing show_posts.js.erb to
$('.posts').html("<%= j render #posts %>");
works. Thank you all for tips!
$('.posts').append("<%= escape_javascript render(:partial => 'posts') %>");
Change your show_posts.js.erb with these contents.
Try this out
$('.posts').html("<%= j render 'post' %>");
Hope this helps!

Issue with Ajax Appending

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);
});
});

Problem using form builder & DOM manipulation in Rails with multiple levels of nested partials

I'm having a problem using nested partials with dynamic form builder code (from the "complex form example" code on github) in Rails. I have my top level view "new" (where I attempt to generate the template):
<% form_for (#transaction_group) do |txngroup_form| %>
<%= txngroup_form.error_messages %>
<% content_for :jstemplates do -%>
<%= "var transaction='#{generate_template(txngroup_form, :transactions)}'" %>
<% end -%>
<%= render :partial => 'transaction_group', :locals => { :f => txngroup_form, :txn_group => #transaction_group }%>
<% end -%>
This renders the transaction_group partial:
<div class="content">
<% logger.debug "in partial, class name = " + txn_group.class.name %>
<% f.fields_for txn_group.transactions do |txn_form| %>
<table id="transactions" class="form">
<tr class="header"><td>Price</td><td>Quantity</td></tr>
<%= render :partial => 'transaction', :locals => { :tf => txn_form } %>
</table>
<% end %>
<div> </div><div id="container">
<%= link_to 'Add a transaction', '#transaction', :class => "add_nested_item", :rel => "transactions" %>
</div>
<div> </div>
... which in turn renders the transaction partial:
<tr><td><%= tf.text_field :price, :size => 5 %></td>
<td><%= tf.text_field :quantity, :size => 2 %></td></tr>
The generate_template code looks like this:
def generate_html(form_builder, method, options = {})
options[:object] ||= form_builder.object.class.reflect_on_association(method).klass.new
options[:partial] ||= method.to_s.singularize
options[:form_builder_local] ||= :f
form_builder.fields_for(method, options[:object], :child_index => 'NEW_RECORD') do |f|
render(:partial => options[:partial], :locals => { options[:form_builder_local] => f })
end
end
def generate_template(form_builder, method, options = {})
escape_javascript generate_html(form_builder, method, options)
end
(Obviously my code is not the most elegant - I was trying to get this nested partial thing worked out first.)
My problem is that I get an undefined variable exception from the transaction partial when loading the view:
/Users/chris/dev/ss/app/views/transaction_groups/_transaction.html.erb:2:in
_run_erb_app47views47transaction_groups47_transaction46html46erb_locals_f_object_transaction'
/Users/chris/dev/ss/app/helpers/customers_helper.rb:29:in
generate_html'
/Users/chris/dev/ss/app/helpers/customers_helper.rb:28:in
generate_html'
/Users/chris/dev/ss/app/helpers/customers_helper.rb:34:in
generate_template'
/Users/chris/dev/ss/app/views/transaction_groups/new.html.erb:4:in
_run_erb_app47views47transaction_groups47new46html46erb'
/Users/chris/dev/ss/app/views/transaction_groups/new.html.erb:3:in
_run_erb_app47views47transaction_groups47new46html46erb'
/Users/chris/dev/ss/app/views/transaction_groups/new.html.erb:1:in
_run_erb_app47views47transaction_groups47new46html46erb'
/Users/chris/dev/ss/app/controllers/transaction_groups_controller.rb:17:in
new'
I'm pretty sure this is because the do loop for form_for hasn't executed yet (?)... I'm not sure that my approach to this problem is the best, but I haven't been able to find a better solution for dynamically adding form partials to the DOM. Basically I need a way to add records to a has_many model dynamically on a nested form.
Any recommendations on a way to fix this particular problem or (even better!) a cleaner solution are appreciated. Thanks in advance.
Chris
I suggest to use another example instead of this. I went also through this process recently and the best implementation is from ryan bates this: http://github.com/ryanb/complex-form-examples/tree/unobtrusive-jquery-deep
If you are using prototype you that's not a problem, you can easily change the implementation to prototype from jquery.

Categories

Resources