Hi want to implement ajax in my ruby on rails tutorials and the controller will return an object on handling the ajax request. I dont know to handle the response in my javascript file.
I want to update some div based on object returned in javascript file.
Here is what I have written in my showcomments.js.erb
$('.show_comment').bind('ajax:success', function() {
$(this).closest('tr')="Something here from the object returned");
});
My link where ajax call is called is via this line of code
<td><%= link_to 'Show Comment', :action => 'showcomment' , :id =>article, :remote => true ,:class=>'show_comment' %></td>
My controller action where this request is handled is like this
def showcomment
#article = Article.find(params[:article_id])
#comment = #article.comments.find(params[:id])
respond_to do |format|
format.js{ render :nothing => true }
end
end
How can this be done?
I just wanted to try and expand on the other answers a little bit.
In rails when you add :remote => true to a link it essentially takes care of the first part of a jquery ajax call. That's why you don't need bind.(ajax:success, function(){ #
do stuff here });
This is a typical jquery ajax call
$.ajax({
url: "test.html",
type: "POST"
}).done(function() {
$( this ).addClass( "done" );
});
Rails takes care of the first part, up to the .done callback. So anything in your javascript erb template is put in the callback like this
.done(function() {
#your showcomments.js.erb file is inserted here
});
To render the showcomments.js.erb template from the controller just do this
def showcomment
#article = Article.find(params[:article_id])
#comment = #article.comments.find(params[:id])
respond_to do |format|
format.js
end
end
You don't need anything after format.js because the default rails action at that point is to render a js template with the same name as the action, in this case it's showcomment.js.erb.
Now you know when that link is clicked it will go straight to rendering that showcomment template , and any javascript in there will be run instantly. Rails makes using ajax very simple. I hope that helps.
change showcomment to this:
def showcomment
#article = Article.find(params[:article_id])
#comment = #article.comments.find(params[:id])
respond_to { |format| format.js }
end
In showcomments.js.erb you can access both objects #article and #comment.
A sample use is as below:
$('#yourdiv').html('<%= #article.name %>');
You render nothing when responding to js format. So code in showcomments.js.erb isn't evaluated. Remove { render :nothing => true } in controller and do whatever you want in showcomments.js.erb. BTW you don't need ajax:success event. It is the end of request already.
showcomments.js.erb
$('.show_comment').closest('tr').html("<%= # you may render partial here or whatever %>");
Related
I have controller Message_Controller and this Controller has method "message" in this method i wanna render .js.erb file i need call js function from rails controller.I need reneder it without html-template(layout) just only js-code in this code i will call js-function with args .How to make it ??
My routes:
post 'chat_bot/message', to: 'chat_bot#message'
My controller:
class ChatBotController < ApplicationController
layout false
def message
#gon.watch.message = params[:text]
#message = params[:text]
puts #message
render partial: 'message.js.erb', layout: false
end
end
my message.js.erb file
alert('<%=#message %>');
With
render partial: 'message.js.erb', layout: false
Rails is going to look for a partial called _message.js.erb right in the folder responding to that controller.
You can use respond_to and there specify the format and what to render:
def message
respond_to do |format|
format.html { render partial: 'message.js.erb' }
end
end
You can skip the instance variable assignation if you prefer, as you have access to the params within the request.
If your idea is to "evaluate" the alert, then it still should be inside a script tag:
<script>
alert("<%= params[:text] %>");
</script>
just update it with
def message
#message = params[:text]
respond_to do |format|
format.js
end
end
Long story short, I have a button. On clicking it, I want an ajax request to be triggered which gets flash[:notice] and displays it in a div in$
Here is my shortened view:
<input type="button" id="search" value="display"/>
<div id="notice">
</div>
My ajax request in the view:
$("#search").submit(function(){
$.ajax({
type: "POST",
url: //url to my show action
success: function(data){
/*$("#notice").html("<%= flash[:notice] %>");
$("#content").html(data);*/
}
});
return false;
});
My controller:
def HomeController < ActionController::Base
def index
end
def show
respond_to do |format|
format.js { flash[:notice] = "" + count.to_s + " results found for " + params[:query][:search_key] + "" }
end
#render :partial => 'search'
end
end
My show.js.erb
#app/views/dashboard_home/show.js.erb
$("#notice").html("<%=j flash[:notice] %>");
$("#content").html("<%=j render partial: "search" %>");
The problem is when I click on button, the notice is displayed fine. But the same notice persists on the next clicks too. The search partial contains the table Please help!
Here is an example that I got working, thanks to Rich Peck's answer. I needed to use flash.now to make sure the flash notice didn't persist.
AJAX trigger in the view:
<%= link_to "Email report", users_path, remote: true %>
Controller:
# app/controllers/users_controller
class UsersController < ApplicationController
def index
# do some things here
respond_to do |format|
format.js { flash.now[:notice] = "Here is my flash notice" }
end
end
end
Rendered view:
# app/views/users/index.js.erb
$("#flash").html('<%= j render partial: "shared/notice_banner" %>');
where the flash notice is displayed in the layout:
# app/views/layouts/application.html.erb
<div id="flash">
<% if notice.present? %>
<%= render partial: "shared/notice_banner" %>
<% end %>
</div>
# app/views/shared/_notice_banner.html.erb
<div data-alert class="alert-box">
<%= notice %>
×
</div>
Sessions
the same notice persists on the next clicks too
This is caused by the flash being stored in the session variable of Rails:
The flash is a special part of the session which is cleared with each
request. This means that values stored there will only be available in
the next request, which is useful for passing error messages etc.
The problem you have is that since I don't think ajax counts as a new request (need reference for this), the data will persist into the next time you request via HTTP.
--
Fix
I would initially try this:
def show
respond_to do |format|
format.js { flash[:notice] = "my secret number "+rand(0,5)+" !" }
end
end
The main problem you have is you're processing the flash variable in your JS using the ERB preprocessor. This is an issue as it means you won't be able to use asset precompile to help it work.
After looking at this question, why not try using the after_filter callback, like this:
#app/controllers/home_controller.rb
Class Home < ActionController::Base
after_filter { flash.discard if request.xhr? }, only: :show
def show
respond_to do |format|
format.js { flash[:notice] = "my secret number "+rand(0,5)+" !" }
end
end
end
--
Update
You should include the success functionality in your show.js.erb:
#app/views/home/show.js.erb
$("#notice").html("<%= flash[:notice] %>");
This means you can remove the whole ajax call from the application.js, and replace with the remote: true for your search form:
#app/views/search/index.html.erb
<%= form_tag home_show_path, remote: true %>
The reason this works is because when you use the format.js respond block, Rails will load the [action].js.erb file in your views. Considering this only happens after the action has been completed, it's equivalent to the success function of your ajax.
By doing this, you'll be able to remove the entire ajax function from your application.js, and replace with the UJS version, as described above
I have the following code:
= link_to "#{icon('heart')} Props".html_safe, vote_picture_path(picture), class: 'tiny radius secondary button vote', method: :put, remote: true
Which goes here:
# VOTE /pictures/1.json
def vote
respond_to do |format|
if #picture.toggle_vote(current_user)
format.json { render json: #picture }
else
format.json { render json: #picture }
end
end
end
And what I'm trying to do is update the total count of votes on a picture via:
$ ->
$(".vote").on "ajax:success", (e, data, status, xhr) ->
vote_count_size = $(".vote-count .size").html()
vote_count_size_integer = parseInt(vote_count_size)
console.info data
However the part that confuses me is the console.info data. It seems to be returning something from a source I can't tell. I'm editing /pictures/show.json.jbuilder but it's not affecting what's coming in from data. I want to return a json structure with the total votes in data so I can update the count on the page from the success callback.
Firstly, your respond_to block can be refactored dramatically:
# VOTE /pictures/1.json
respond_to :json
def vote
#picture.toggle_vote(current_user)
respond_with #picture
end
This should return a JSON object for your #picture var. You'll have to detail what data you're getting in your console? If you provide the data you're receiving back, it will be a huge help!
You should respond with a javascript file (vote.js.erb) within this you can mix javascript and erb expressions to change the desired page element:
$('.vote-count .size').html('<%=#picture.vote_count%> votes');
your controller would look like:
# VOTE /pictures/1.js
def vote
respond_to do |format|
#picture.toggle_vote(current_user)
format.js
end
end
My plan was to update a partial via a klick-event where I fetch some data via ajax.
So i opened my assets/javascripts directory and put the code in the js file of the module I planed to call it on. I managed to fetch the data and to call some "html() or text()" on the div. But as soon as I tried to call
.html("<%= escape_javascript( render( :partial => 'job') ) %>")
my controller told me unknown method "render". So I red in many other Threats that the assets directory was not build for static content.
But now comes the question where to put it if not in assets?
I tried to put it in the view/model folder (with the same name as the aktion 'show'). But it wouldn't load. Yes I told the Controller in the show action to respond_to format.js.
So where should I put the js-File and how to call it? Or is there even a method to let it in the assets-directory and beeing able to call render?
Thanks for your answer! Sadly I do exactly that but I doesnt work. So here is my Code:
/app/views/events/show.js.erb.coffee:
$(document).ready ->
url = window.location
url = String(url).split('/')
event_id = url[$.inArray( "events" , url) + 1]
$('.position').click ->
position_id = $(this).attr("id")
$.ajax '/events/'+event_id+'/eventpositions/'+position_id+'/eventjobs'
dataType: 'json'
success: (result)->
$( '#'+position_id ).find('.jobs').html("<%= escape_javascript( render( :partial => 'job') ) %>")
alert result[1].job_id
/app/views/events/show.html.haml:
%p#notice{:xmlns => "http://www.w3.org/1999/html"}= notice
%p
%b Name:
= #event.name
\
%b Plz:
= #event.plz
%p
%b Personal:
- #eventpositions.each do |p|
.position{:id => "#{p.id}"}
%b
Position: #{Position.find(p.position_id).name} Anzahl: #{p.quantity} Aufträge: #{p.eventjobs.all.count}
.jobs
= link_to 'Neuer Auftrag', new_event_eventposition_eventjob_path(#event.id,p.id)
%br
%br
= link_to 'Neue Position', new_event_eventposition_path(#event.id)
= link_to 'Edit', edit_event_path(#event)
|
\#{link_to 'Back', events_path}
/app/views/events/_job.html.haml:
.jobs
- eventjobs.each do |j|
User: #{User.find(Job.find(j.job_id).user_id).email}
%br
/app/controllers/events_controller.rb:
def show
#agency = Agency.find(current_agent.agency_id)
#event = #agency.events.find(params[:id])
#eventpositions = #event.eventpositions.all
respond_to do |format|
format.html # show.html.erb
format.json { render json: #event }
format.js
end
end
So the Code does work without Javascript. All renders and is fine. But my main Problem now is that it wont even react to a click event if I place it in the app/views/events Folder. As soon as I place it in the assets directory I works like a charm, but wont render.
So what am I missing? Why does my js Code does not get loaded?
Thanks a lot for your help!
Generally for this kind of thing, I'll name it the same as a particular action, such as show.js.erb, and then use the format.js as you have in the controller. If you're using coffeescript, it will need to be named show.js.coffee.erb. If this does not work, can you post the code of your view where this onclick event is setup?
Edit for using the show javascript code
Because you're using the show action, should just be able to do this:
= link_to "Show", #event, :remote => true, :format => :js
Adjust the event variable there as you need to, but it should work
I would love to be able to have an ERB partial like this:
<ul id='things-index'>
<% #things.each do |t| %>
<li><%= t.name %></li>
<% end %>
</ul>
And be able to update it in the controller like so:
class ThingsController < ApplicationController
def create
#thing = Thing.new(params[:thing])
#thing.save
respond_to do |format|
format.html
format.js do
#things = Thing.all
page.replace('things-index')
end
end
end
end
Meaning that JavaScript would be sent as a response without me having to explicity write a js.erb template like the following create.js.erb:
$('#things-index').replaceWith('<%= escape_javascript(render("things/index")) %>')
There may be something like this already, either built in to Rails or available as a gem, but if there is, I'm not aware of it.
I suppose ideally, it would re-render the 'index' action via JS and send the update to the browser, so it might look more like this:
respond_to do |format|
format.html
format.js do
render 'index'
end
end
And know to replace #things-index (or allow me to explicitly specify it).
Update
Whoops...Apparently there was page.replace_html when Prototype was part of Rails, but that functionality has been replaced by the .js.erb template method. That seems much less DRY to me (tons of near-identical js.erb templates), so if anyone has a solution, I'd appreciate it.
You can pass whatever you want to your js.erb, including what to replace, and with what.
$('<%= #id %>').replaceWith('<%= escape_javascript(render(#renderable)) %>')
Note Even in 2012 this wasn't really a recommended way of doing things like this. These days (early 2015) I'd say it's even less recommended given the great client-side technologies available.
Another solution would be to send back just the data, for the client to render as it choses:
respond_to do |format|
format.html
format.json do
#things = Thing.all
render :json => #things
end
end
And on the client side:
function updateList(data){
var $item,
$list = $('#things-index');
$list.find('li').remove();
$.each(data, function(i, item){
$item = $('<li />').text(item.name);
$list.append($item);
});
}
$.getJSON('/my/route.json', function(data){
updateList(data);
});