I am trying to render a partial after ajax call using coffee script but could not make it.
Controller which is called on AJAX request
def unfollow
#user = User.find(params[:follow][:followed_id])
current_user.unfollow!(#user)
render json: {result: "success"}
end
partial: User/follow.html.erb
<div id="follow_button">
<%=form_for(:follow,url: follow_users_path,remote:true) do |f| %>
<%= f.hidden_field :followed_id, value: #user.id %>
<%= f.submit "Follow", id: "Follow_button", class: "btn btn-primary" %>
<% end %>
</div>
Ajax:success function
$ ->
$('#unfollow_button').on "ajax:success", (e,data,status,xhr) ->
$('#follow_unfollow_button').html("<%= escape_javascript( render partial: 'users/follow') %>")
HTML which is on That place
<div id="unfollow_button">
<%=form_for(:follow,url: unfollow_users_path,remote:true) do |f| %>
<%= f.hidden_field :followed_id, value: #user.id %>
<%= f.submit "Unfollow", id: "unfollow_button", class: "btn btn-primary" %>
<% end %>
</div>
I am not getting any value from the server I just want to render it when ajax success. But it render like this
<%= escape_javascript( render partial: 'users/follow') %>
How to solve this? what am I missing?
Yeah you can't render an erb partial inside javascript from a json response like that. Here's how to fix
1) remove this line from the controller
render json: {result: "success"}
2) In views/users/ create a file called unfollow.js.coffee with the following code
$('#follow_unfollow_button').html("<%= j render('users/follow') %>")
3) You no longer need to bind to ajax success function so delete this code completely from wherever you had it
$ ->
$('#unfollow_button').on "ajax:success", (e,data,status,xhr) ->
$('#follow_unfollow_button').html("<%= escape_javascript( render partial: 'users/follow') %>")
Don't try to render it from the coffeescript in this case. Instead, render the result from controller and return that as data to ajax.
1) Change controller method to
def unfollow
#user = User.find(params[:follow][:followed_id])
current_user.unfollow!(#user)
render 'users/follow', :layout => false
end
2) Change JS function to
$ ->
$('#unfollow_button').on "ajax:success", (e,data,status,xhr) ->
$('#follow_unfollow_button').html(data)
As your controller will return something (and not an error), the ajax:success will fire up and instead of trying to render it in JS/coffeescript, just render it in controller and that way, you also don't need to render something just for the sake of returning information to client.
Related
Trying to get a flash message and render a partial on an ajax call with link_to and remote:true
I have in my controller examples.rb:
def create
* Some stuff happens *
respond_to do |format|
format.js
format.html do
flash[:notice] = "Works!"
redirect_back(fallback_location: root_path)
end
end
end
I have the "link_to" form in _one_partial.html.erb
<%= link_to examples_path(whatever: locals[:whatever]), class: "whatever", method: :post, remote: true do %>
<div class="whatever_vix">
<p> Click Here! </p>
</div>
<% end %>
which is in a view as:
<div id="addhere">
<%= render 'favorites/one_partial', locals: {whatever: #whatever} %>
</div>
and in create.js.erb
$('#addhere').append("<%= j render 'whatever/another_partial' %>")
The ** some stuff happens ** part in my controller obviously works, but the new partial in create.js.erb doesn't show, neither the flash message appears once I add remote:true to the "link_to" form
I'm new to Ruby on Rails and trying out an application. My application does Ajax calls correctly, but the response is shown as a js.erb file in the browser. How do I show a json response while executing the js.erb file? Is it possible or is there a better way?
Thank you.
My Controller File
def new
#department = Department.new
# respond_to do |format|
# format.html
# format.json {render json: #department}
# end
end
def create
#departments = Department.all
#department = Department.create(department_params)
respond_to do |format|
format.html
format.js {render json: #department}
end
end
Controller
My Form Partial
<div class="modal-dialog">
<div class="modal-content">
<%= form_for #department, remote: true, data: {type: :json} do |f| %>
<div class="modal-body">
<h2> Department: </h2>
<ul class="errors"></ul>
<div class="form-group">
<%= f.label :title, class:"control-label" %>
<%= f.text_field :title, class: "form-control" %>
</div>
<div class="form-group">
<%= f.label :body, class: "control-label" %>
<%= f.text_field :body, class: "form-control" %>
</div>
</div>
<div class="modal-footer">
<%= f.submit class: "btn btn-primary .departmentCreate" %>
<%= link_to "Cancel", "#", class: "btn", data: {dismiss: "modal"} %>
</div>
<% end %>
</div>
</div>
Form.html.erb
My Json Response if I keep format.js {render json: #department}
Json Response
My Response if I remove render json from controller:
JS response
My new.js.erb File
$("#department-modal").html("<%= escape_javascript(render 'departments/new') %>")
$("#department-modal").modal("show")
My _new.html.erb partial :
<%= render "form" %>
My create.js.erb file:
<%= render 'save' %>
My _save.js.erb partial:
$("ul.errors").html("")
<% if #department.errors.any? %>
<% #department.errors.full_messages.each do |message| %>
$("ul.errors").append($("<li />").html("<%= message.html_safe %>"))
<% end %>
<% else %>
$(".department-index").html("<%= escape_javascript(render 'departments/index') %>")
$("#department-modal").modal("hide")
While rendering the json response in browser, the js.erb file doesn't execute. How can I show json response in browser while js.erb file executes?
Thank you :)
How can I show json response in browser while js.erb file executes?
Thank you :)
If I understood correctly what you are asking, the answer is you can't. Your response's Content-Type will be either an application/json or an application/javascript.
The browser will use this header to handle the response.
The reason your JavaScript is not executing is because you have a block present in your controller that handles the response. So the code will never reach your JavaScript file.
Change the line:
format.js { render json: #department }
to:
format.js
This will tell Rails that you accept JavaScript request, and since no block is specified the template in "app/views/departments/create.js.erb" is used.
If you don't want to render the default template you can specify it in the block like so:
format.js { render: :new } # renders app/views/departments/new.js.erb
or:
format.js { render: 'some/path' } # renders app/views/some/path.js.erb
Instead of nested rendering of js.erb direct render template from controller with full path. assuming full path of _save.js.erb is departments/save
Also #departments should be calculated after create new department so that newly created record will be added with #departments
def create
#department = Department.create(department_params)
#departments = Department.all
render template: 'departments/save'
end
Its always a good practice to pass local variables with partial:_
$("ul.errors").html("")
<% if #department.errors.any? %>
<% #department.errors.full_messages.each do |message| %>
$("ul.errors").append($("<li />").html("<%= message.html_safe %>"))
<% end %>
<% else %>
$(".department-index").html("<%= j render 'departments/index', departments: #departments) %>")
$("#department-modal").modal("hide")
You cannot render both as such, but you can render the partial on the server side, and store the result in the JSON. On the client side, you can process JSON, and extract and use the rendered HTML snippet in JS code.
Syntax in Jbuilder for rendering a partial :
json.some_key json.partial! 'my_partial.js.erb'
So the stack is something like..
Controller
# Render the JSON partial in views
respond_to do |format|
format.json {}
end
View - controller action will call default json builder for action e.g views/departments/new.json.jbuilder
In here render any original JSON you wanted, like #department, but also render the required JS partial and store it in the JSON
json.department #department
json.department_form json.partial! 'new.js.erb'
Then in the client code that receives the JSON, for example as data, the partial will be present under key department_form, and you can assign the rendered form, to an html placeholder element in your original view
//... ajax call to your controller#action
dataType: "json",
success: function(data) {
$("#department_form_placeholder").html(data['department_form'])
I am trying to render a partial with ajax when submitting a form.
Here is my code:
index.html.erb
<% #inbox.each do |conversation| %>
<div class="message">
<div id="messages">
<%= render conversation.messages %>
</div>
<div class="inner-message">
<%= form_tag({controller: "conversations", action: "reply", id: conversation.id}, {remote: true, method: :post}) do %>
<%= hidden_field_tag :recipient_id, current_user.id %>
<%= hidden_field_tag :subject, "#{current_user.name}" %>
<div class="form-group">
<%= text_area_tag :body, nil, class: "form-control", placeholder: "Odgovori" %>
</div>
<div class="form-group">
<%= submit_tag 'PoĊĦlji', class: "btn btn-primary" %>
</div>
<% end %>
</div>
</div>
<% end %>
index.js.erb
$("#messages").html("<%= escape_javascript(render conversation.messages) %>")
conversations_controller.rb
def reply
conversation = current_user.mailbox.conversations.find(params[:id])
current_user.reply_to_conversation(conversation, params[:body])
respond_to do |format|
format.html { redirect_to messages_path }
format.js { redirect_to messages_path }
end
end
when I submit the form, I get an undefined local variable error:
ActionView::Template::Error (undefined local variable or method
`conversation' for #<#:0x007fd287172fa8>)
How do I pass the local variable from the loop to the .js.erb view?
Thanks!
I usually don't do much rendering of js in applications so I'm a bit rusty on the specifics. However there are a couple of problems with your code.
First by issuing a redirect your instructing the browser to load a new url . Any variables such as 'conversation' that you would have set would be forgotten.
As the Stan Wiechers alluded you need to use an instance variable (e.g. #conversation) if you want to preserve conversation for the view. Unfortunately that won't help you in this case because of the redirect which wipes out all variables not stored in the session, cookies, or flash hash.
What I think you want to do is render your partial in stead of redirecting. Typically when you are using ajax you don't want to reload the page on the server side. In Rails you would typically render json or in your case a js partial.
Try
format.js{render partial:[PARTIAL NAME], locals:{conversation: conversation} }
This will render the partial without redirecting and will pass your local variable. If you change 'conversation', to #conversation then you can leave off the locals:{conversation: conversation} but your partial should reference
#conversation
not
conversation
hope that helps
the following renders "2" in the div as it should when a form is submitted.
full brands/create.js.erb version 1:
$("#brand_ajax").html("1")
$("#brand_ajax").html("0")
$("#brand_ajax").html("2")
partial brands/show_brands.html.erb
The div I want to refresh
<% for brand in #brands%>
ID: <%= h brand.id %>
<% end %>
partial cars/show.html.erb
The ajax call
<%= form_for([#car, #car.brands.build], **remote: true**) do |f| %>
<%= f.fields_for :brandsdo |a| %>
<%= a.text_field :name, placeholder: "New Manufacturer" %>
<% end %>
<%= f.submit "+", class: "btn inline" %>
<% end %>
**/*The div I want to refresh*/**
<div id="brand_ajax">
<%= render 'brands/show_brands' %>
</div>
The brands controller
respond_to do |format|
if #brand.save
format.html { redirect_to #car }
format.js
else
flash[:notice] = "Error!"
format.html { redirect_to #car }
end
end
the following does not render "2" after submitting a new brands form - does not refresh at all. just shows the old version of
'show_brands'.
full brands/create.js.erb (to illustrate)
$("#brand_ajax").html("1")
$("#brand_ajax").html("<%= escape_javascript render 'show_brands' %>")
$("#brand_ajax").html("2")
any ideas why such a thing should happen?
Try
$("#brand_ajax").html("<%= j render :partial => 'show_brands' %>")
Thanks for reading!
So I'm relatively new to RoR (Rails 5) and I try to render posts of a user in a partial (_posts_panel.html.erb) which contains another partial: the navigation (_posts_navigation.html.erb). I'm using ajax to show the posts when clicked on in the navigation which is working fine.
Now I want to use it for deleting a post. The post is destroyed when I click on the button and I managed to remove it in navigation.
What is not working:
the next post should be shown in the panel after the deletion
when there is no post left I want to reload the panel because another partial (_posts_empty.html.erb) should be rendered
My Code:
_posts_panel.html.erb: (it is rendered in show.html.erb of user)
<% if #user.simple_posts.empty? %>
<%= render 'simple_posts/shared/posts_empty' %>
<% else %>
<div id="post-navigation">
<%= render 'simple_posts/shared/posts_navigation' %>
</div>
<%= simple_posts_edit_button(current_user, #simple_post)%>
<%= simple_posts_delete_button(current_user, #simple_post)%> #button helper
<div id="show_post">
<%= render #simple_post %>
<%= yield %>
</div>
<%end %>
_posts_navigation.html.erb
<div class="bootstrap-vertical-nav">
<ul class="nav flex-column">
<% #user.simple_posts.reverse_each do |post|%>
<li class="nav-item" id="<%= #simple_post.id %>">
<%= link_to post.title, user_simple_post_path(#user, post), remote: true, class:"nav-link text-dark" %>
</li>
<% end %>
</ul>
</div>
<% if #user.id == current_user.id %>
<%= link_to "+ New Post", new_user_simple_post_path(current_user), class: "btn btn-info w-100", role: "button" %>
<% end %>
destroy.js.erb
$('li#<%= #simple_post.id %>').remove();
simple_posts_controller.rb
def destroy
#simple_post.destroy
#simple_post =current_user.simple_posts.first
respond_to do |format|
# format.html { redirect_to simple_posts_url, notice: 'Simple post was successfully destroyed.' }
format.js
end
end
I tried to append in destroy.js.erb the same code from showing the post $('#show_post').html("<%= escape_javascript render #simple_post %>"); but it's not working correctly. When deleting the first post (but only that one) the next one is shown but the post is not removed from the navigation. I also tried $('#post-navigation').html("<%= escape_javascript render partial: 'simple_posts/shared/posts_navigation' %>"); and it nothing happens.
Also I tried to reload the whole panel with $('#post-panel').html("<%= escape_javascript render partial: 'simple_posts/shared/posts_panel' %>");in show.html.erb of user but again: nothing. I'm not sure if I have to specify in which view or partial exactly it has to render the partial.
I don't really know how to approach this further.
Edit 1
ButtonHelper.rb
def simple_posts_delete_button(current_user, simple_post)
if(current_user.id == #user.id)
link_to svg('x-square'), [current_user, simple_post], remote: true, method: :delete, class:"btn"
end
end
Edit 2
show-action from simple_posts_controller.rb
def show
#user = User.find{params[:id]}
#simple_post = SimplePost.find(params[:id])
respond_to do |format|
format.js
format.html # show.html.erb
end
end
show.js.erb
$('#post-actions').html("<%= j render partial: 'simple_posts/shared/posts_actions', locals: {simple_post: #simple_post, user: #user} %>");
$('#show-post').html("<%= j render #simple_post %>");
There are several problems with your partials:
First, to remove the post from your navigation you just need to update the partial, the post is already destroyed/removed at this point.
After destroy, #simple_post in your button helper is not updated with ajax and still comes from the users_controller (where you set it the first time i presume)
You can put your action buttons inside a new partial and specify the locals.
You can also wrap the html inside a main div for the last update (when all the posts are deleted)
_posts_panel.html.erb:
<div id="panel">
<% if #user.simple_posts.empty? %>
<%= render 'simple_posts/shared/posts_empty' %>
<% else %>
<div id="post-navigation">
<%= render partial: 'simple_posts/shared/posts_navigation', locals: { simple_post: #simple_post } %>
</div>
<div id="post-actions"> #<-- new partial
<%= render partial: 'simple_posts/shared/posts_actions', locals: { simple_post: #simple_post } %>
</div>
<div id="show_post">
<%= render #simple_post %>
<%= yield %>
</div>
<% end %>
</div>
_posts_actions.html.erb:
<%= simple_posts_edit_button(current_user, simple_post)%>
<%= simple_posts_delete_button(current_user, simple_post)%>
Note that you are not using the instance variable #simple_post anymore but the local one.
Now you can write your js like this:
destroy.js.erb:
<% if #simple_post %> //<-- check if "#simple_post = current_user.posts.first" still exists after destroy
$('#post-navigation').html("<%= j render partial: 'simple_posts/shared/posts_navigation', locals: { simple_post: #simple_post } %>");
$('#post-actions').html("<%= j render partial: 'simple_posts/shared/posts_actions', locals: { simple_post: #simple_post } %>");
$('#show_post').html("<%= j render #simple_post %>");
<% else %>
$('#panel').html("<%= j render partial: 'simple_posts/shared/posts_empty' %>");
<% end %>