In my project I show last 4 comments on a post and then when someone click on the expand comments link rest of the comments should show. I have following code
<%= link_to demo_expand_comments_path(:post_id => post.id, comment_id => comment_id ), remote: true do %>
This is the link to expand comment.
<div id="comments_container_<%= post.id %>">
<%= render :partial => 'community/comments/comment_box_posts', :collection => post.comments.order('id DESC').limit(4).reverse, :as => :comment %>
</div>
Here I am rendering first 4 comments
Now when someone click on expand comments, expand_comments action is called and in expand_comment.js.erb has following code
$('#comments_container_<%= #post_id %>').prepend('<%= escape_javascript(render :partial => 'community/comments/comment_box_posts', :collection => #comments, :as => :comment) %>');
controller action
def expand_comments
#post_id = params[:post_id]
post = Post.find(params[:post_id])
#comments = post.comments.where('id < ?', params[:comment_id]).order("created_at ASC")
I need the last shown comment_id here
respond_to do |format|
format.js{}
end
end
Now what I need help is that when expand comments action is called I want to send the post id and the last comment id I am showing now.
There are several ways to do this. You can change your "expand comment" link as well as you render comments.
In controller:
def expand_comments
...
#comment_id = #comments.last.id
Then in expand_comment.js.erb:
$('#comments_container_<%= #post_id %>').prepend('<%= escape_javascript(render :partial => 'community/comments/comment_box_posts', :collection => #comments, :as => :comment) %>');
$('#id_of_link').attr('href', '<%= demo_expand_comments_path(:post_id => #post_id, comment_id => #comment_id ) %>');
But it is not way I like.
Don't send comment_id parameter like url parameter. You should send it by ajax request.
Remove comment_id parameter from url, store it like data-attribute:
<%= link_to demo_expand_comments_path(:post_id => post.id), data: {comment_id: #comment_id} do %>
This is the link to expand comment.
...
Note that you have to remove "remote: true" from link_to too.
Send ajax request when link clicking:
$('#id_of_link').click(function() {
$.ajax({
type: "get",
url: $(this).attr('href),
data: { comment_id: $(this).data('comment_id') },
dataType: 'script'
});
return false;
});
And update comment_id attribute when comments rendering:
$('#comments_container_<%= #post_id %>').prepend('<%= escape_javascript(render :partial => 'community/comments/comment_box_posts', :collection => #comments, :as => :comment) %>');
$('#id_of_link').data('comment_id', '<%= #comment_id %>');
Related
I am having a difficult time trying to get my partial to refresh on button press. I want to simply refresh the div, and not the whole page. Here is what I have in the view:
<div id="ajax">
<%= render 'layouts/confessions' %>
</div>
Then in my partial _confessions.html.erb, I have some basic html and two buttons similar to this:
<%= form_tag( { :controller => :confessions, :action => :upvote, :id => conf.id }, { :method => :put } ) do %>
<%= submit_tag 'Like' %>
<% end %>
My confessions_controller.rb:
def upvote
#confession = Confession.find(params[:id])
Confession.increment_counter :upvotes, #confession
respond_to do |format|
format.js
end
end
And finally, upvote.js.erb:
$('#ajax').html("<%= escape_javascript(render(:partial => 'confessions')).html_safe %>");
The action of submitting to my database is working, but the page is now redirecting to /upvote?id=9 (id can be different), instead of just refreshing the div. What am I doing wrong? I am new to Rails, so I could be missing something completely obvious...
EDIT: Here is my folder structure:
My view: views/pages/home.html.erb
My partial: views/layouts/_confessions.html.erb
My Controller: controllers/confessions_controller.rb
My js.erb file: views/confessions/upvote.js.erb
After rake routes
confessions GET /confessions(.:format) confessions#index
POST /confessions(.:format) confessions#create
new_confession GET /confessions/new(.:format) confessions#new
edit_confession GET /confessions/:id/edit(.:format) confessions#edit
confession GET /confessions/:id(.:format) confessions#show
PUT /confessions/:id(.:format) confessions#update
DELETE /confessions/:id(.:format) confessions#destroy
upvote /upvote(.:format) confessions#upvote
downvote /downvote(.:format) confessions#downvote
root / pages#home
Make sure you have this in your application.js
//= require jquery
//= require jquery_ujs
FYI: Rails form_for :remote=>true is not calling js method
Then, change this,
$('#ajax').html("<%= escape_javascript(render(:partial => 'confessions')).html_safe %>");
To:
$('#ajax').html("<%= escape_javascript(render(:partial => 'layouts/confessions')).html_safe %>");
Add :remote => true
<%= form_tag( { :controller => :confessions, :action => :upvote, :id => conf.id }, { :method => :put, :remote=>true } ) do %>
Also - read up on rails routes to see how to setup the route for PUT confessions/upvote.
http://guides.rubyonrails.org/routing.html#adding-more-restful-actions
i'm trying to get the content of a div to change when i click a link. i can see from the console that the partial and the js is being rendered, however, my html does not update
in index.html:
<div id="test">this is supposed to change</div>
...
<%= link_to 'planner', test_path(:budget => "b2", :size => "g2", :age => "a1", :activity => "l2", :tourist => "t2", :city => "boston"), :method => :get, :remote => true, :id => "linkto" %>
in my planner_controller:
respond_to do |format|
format.html
format.js {render :layout => false}
in update.js.erb:
$("#test").update(" <%= escape_javascript(render('load')) %>")
_load.html file:
<p> test </p>
could the error be that i'm just testing the code, and not actually doing anything with the results of the query?
You are updating an element with an id of test but you don't have that element anywhere on your page.
$("#test").update(" <%= escape_javascript(render :parial => "load") %>")
Try this
You can use replaceWith() in place of update()
$("#test").replaceWith(" <%= escape_javascript(render('load')) %>")
I am trying to create a paginated index view in Rails 3.2 with a drop down menu to select the number of items displayed per page. I am using the will_paginate gem and the pagination function is working great.
However, with my current setup shown below, I am getting validation errors when changing the drop down menu selection. It appears to be trying to create or save a Contact model instead of just making another request to the index action. Any help will be greatly appreciated.
Here is my index action:
def index
#logic here to set per_page value depending on request?
#contacts = Contact.paginate(page: params[:page], :per_page => 20)
end
Here is my index.html.erb view with my attempt at a drop down menu for items per page:
<%= form_tag({ :action => "index", :method => "get" }, { :id => "contacts-index" }) do %>
<%= select_tag(:view, options_for_select([["10", 10], ["25", 25], ["50", 50]]), { :id => "switch-view" }) %>
<% end %>
<% #contacts.each do |contact| %>
<%= contact.first_name %><%= contact.last_name %>
<% end %>
Lastly, here is the jQuery I am using to try to submit the new request to contacts#index when the items per page is changed:
$(document).ready(function() {
$("#switch-view").change(function() {
$("#contacts-index").submit();
});
});
:method => get should be moved out of the first hash.
<%= form_tag({ :action => "index"}, { :method => "get", :id => "contacts-index" }) do %>
Without this, it's doing a post and submitting the 'method' as a param. A post to the 'index' url will result in the validation errors you're seeing.
Problem description:
I have a view with set of links:
<% #feeds.each do |f| %>
<div class="feed">
<span class="feed_counts"> <%= f.display_counts %> </span>
<%= link_to "refresh", { :controller => 'Feeds', :action => "refresh_feed", :feed_id => f.id}, :remote => true, :class => 'refresh_feed_link' %>
</div>
<% end %>
Users click on the link and launch next controller method:
def refresh_feed
#feed = Feed.find(params[:feed_id])
#feed.parse
end
Now I want to change the content of the corresponding span-element to #feed.total_count value.
My attempts:
Well, as I know there is a two way's to do it without reloading whole the page:
Way 1:
I can include js in my layout:
<%= render :partial => 'shared/partial_js' %>
and use this code in the partial_js:
<script type="text/javascript">
$().ready(function() {
$('.refresh_feed_link').bind('click', function() {
$(this).closest('.feed').find('span.feed_counts').text('woo');
});
});
</script>
In this case I have '$(this)' and I can find the corresponding 'span' element. But I don't have any possibility to get my #feed varible value.
Way 2:
I can add
respond_to do | format |
format.js {render :layout => false}
end
to my controller and create refresh_feed.js.erb file. In this JS file I can use my variable as <% #feed.total_count %>, but I don't know which of my multiple links was clicked. In the other words the $(this) variable in this file will be (window) and I cannot find corresponding span-element.
Question:
Is there any way to get what I want ?
Thanks in advance.
There are lots of ways to do this. Using the wayds that you described, here's a simple solution for the "which link was clicked" problem: dom_id.
1) Make a partial: app/views/feeds/_feed.html.erb
<%= div_for feed do %>
<span class="feed_counts"> <%= feed.display_counts %> </span>
<%= link_to "refresh", { :controller => 'Feeds', :action => "refresh_feed", :feed_id => feed.id}, :remote => true, :class => 'refresh_feed_link' %>
<% end %>
2) In your view:
<%= render #feeds %>
3) In your refresh_feed.js.erb file:
$('<%= dom_id(#feed) %>').replaceWith('<%= escape_javascript( render #feed ) %>');
There's another way that I personally like better, but it will take a me a little while to write it up, so I'll leave this for you here while I write up the other way.
Second Way
Here's how I do it, using CoffeeScript and HAML because they're easier to type. You can just convert this to plain JS and ERB and it will work the same.
I would setup my routes like so:
resources :feeds do
get "refresh_feed", :on => :member
Assuming you've got a "feed" partial, app/views/feeds/_feed.html.haml:
= div_for feed, :class => 'feed_widget' do
%span.feed_counts= f.display_counts
= link_to "Refresh", refresh_feed_path(f), :class => 'refresh_link'
In any view:
= render #feeds
// or, more explicit:
= render :partial => 'feed/feeds', :collection => #feeds, :as => :feed
Now, in app/assets/javascripts/feeds.js.coffee
# Global Scope for CoffeesScript, ignore for JS
root = exports ? this
# Check page if there are feed widgets on it and initialize a handler for each one.
jQuery ->
if $('div.feed_widget').length
$('div.feed_widget').each ->
new FeedWidget $(this)
root.FeedWidget = (container) ->
#container = container
#refresh_link = #container.find('a.refresh_link')
#feed_counts = #container.find('span.feed_counts')
this.initialize()
root.FeedWidget.prototype =
initialize: ->
self = this
#feed_counts.click (event) ->
event.preventDefault()
$.ajax
type: 'GET'
url: self.refresh_link.attr 'href'
dataType: 'json'
error: (xhr, status, error) ->
console.log error
console.log xhr
success: (data, status, xhr) ->
self.feed_counts.text data.feed_counts
Then in your controller:
def refresh_feed
#feed = Feed.find(params[:id]) #assuming you have a resourceful route to this.
#feed.parse
respond_to do |format|
format.js { render :json => { feed_counts: #feed.counts }, :status => :ok } # use whatever method gets you the feed count here.
end
end
Now you are getting a JSON response that is just the feed count, and you have a single JS listener/handler widget that will automatically show up (and function) and place you render that partial. Cool huh?
Note, the above code is not tested since I don't have your app, so you'll have to refine it for your needs. But ask questions and I'll do my best to answer.
Good luck!
I have a form that when I click submit, should update a partial that is on the same page...
When I place this here:
page.replace_html 'show_cards_div', 'Hello'
It does just as it should, display hello when I need it to. But when I make it into this....
page.replace_html 'show_cards_div', :partial => "reloadThisPartial"`
It simply does not do anything. What am I doing wrong?
The request might not be an Ajax call. Make Ajax call. User remote_form_for instead of form_for or use jquery.form for sending ajax calls to controller. If you are using jquery then do something like:
<%= javascript_include_tag "jquery-1.4.4.min.js", "jquery.form" %>
<%= form_for :user, :url => {:controller => "come_controller",:action => "some_action"}, :html => {:id => 'form_id', :class => 'cmxform', :onsubmit => "return false;"} do |f| %>
......................................
<% end %>
<script type="text/javascript">
$('#form_id').submit(function() {
var container = $("#show_cards_div");
$(this).unbind('submit').ajaxSubmit({
success: function(data) {
container.html(data);
}
})
return false
});
</script>
in controller do something like this.
render :partial => "reloadThisPartial", :layout => false, :locals =>{:users =>#users}