I am using Rails remote true for ajax calls, but I have error in handling the response form controller.
What I am doing is I have placed a form in partial which I render in the view for the first time, and I have also given it a id in html options for form_for. I have also applied some jQuery on that form like on save and cancel button and one script for date picker on one of its field.
As I handle the response from server using format.js for rendering js file, in which I have placed the code as follows
if #vairable.save
format.js { render 'some-file' }
else
format.js { render 'something'}
end
If the variable saved successfully I close the form properly, but if validations occur I render the form again by writing JavaScript code in js.erb file. I have problem in handing this response. The errors are displaying properly but when the form renders again with errors, the jQuery events applied to its fields and button, do not work. The jQuery events don't take place.
This problem only occurs when the model validations occurs and the validation rails are displayed with the new render form.
You should wrap your response in a respond_to block like this:
respond_to do |format|
if #variable.save
format.js { render 'some-file' }
else
format.js { render 'something'}
end
end
Edit: Your jQuery tags should be changed to $(document).on(...). Eg.
#change this:
$("#your-target-id").click(function(){
alert("This doesn't work after your have submitted via ajax")
});
#to this:
$(document).on("click", "#your-target-id", function() {
alert("This should work after ajax submission, and when errors are displayed");
});
Related
In my controller:
respond_to do |format|
format.html { redirect_to handlers_url }
format.js { render #handler, layout: false }
end
In my handlers.coffee file:
$ ->
$('body').on 'ajax:error', '#new_handler', (event, data, status, error) ->
console.log error
$('body').on 'ajax:complete', '#new_handler', (event, data, status) ->
console.log status
$('#new_handler').remove()
$(data.responseText).prependTo('tbody')
On the surface, this works in that the data (rendered using the _handler.html.erb file) is appended to the tbody element. But it won't work if I change ajax:complete to ajax:success, and the ajax:error fires every time with:
parsererror
SyntaxError: Unexpected token <(…)
It looks like the error is because I'm rendering HTML from the _handler.html.erb template and jQuery is expecting pure JS. But I'm not sure how to send pure JS without using a separate create.js.coffee file, which I'm trying to avoid.
Any ideas on how I can accomplish that in the controller without creating the extra javascript view?
You could try creating a .js.erb partial or file to handle the format.js response. You could copy the code from your current html partial and then use a jquery/javascript append/prepend/before method to place the generated HTML wherever you need to.
My Rails app contains an Excel-like editable table, using best_in_place fields throughout. They work perfectly fine upon page load and I have no problem calling coffeescript functions on ajax:success after a user edits a best_in_place field.
Since this is an Excel-like table, users can click a link to add a new placeholder row to the table. My create.js.erb file adds the row without a page reload. The new row has several table cells with best_in_place functionality, and updating them updates the database, so far so good.
The problem is that when a user then edits a best_in_place fields in one of the new rows, ajax:success does not fire, therefore my coffeescript functions do not initiate.
I've confirmed the new table cells have the exact same class and data attributes as the existing table cells (ajax:success is read on the class name).
Question- in this scenario, how do I initiate my coffeescript function if ajax:success is not being recognized?
Milestone controller, both create and update actions
def create
#payment_schedule = PaymentSchedule.find(params[:id])
build_default_milestone # this builds a placeholder milestone
if #milestone.save
increment_milestone_positions # this relates to a sortable table
respond_to do |format|
format.js
format.html { redirect_to :back }
end
else
respond_to do |format|
format.js
format.html { redirect_to :back }
end
end
end
def update
#milestone = Milestone.find(params[:id])
respond_to do |format|
if #milestone.update(milestone_params)
update_milestone_amounts
format.html { redirect_to(:back) }
format.json { respond_with_bip(#milestone) }
else
format.html { redirect_to(:back) }
format.json { respond_with_bip(:back) }
end
end
end
Create.js.erb
$('#milestone-body').prepend('<%= escape_javascript(render partial: 'row_add', locals: { milestone: #milestone }) %>');
Coffeescript function
update-percent is the class name of the best_in_place field in question. This function fires perfectly for the existing rows, just not the new ones.
$('.update-percent').on 'ajax:success', (event, data, status, xhr) ->
...
Any suggestions on how to solve this?
The issue is resolved. The problem was not that ajax:success wasn't firing, it's that (for reasons still unknown) I had to read ajax:success at the table body level instead of the table cell in question. Apparently this is a somewhat common issue, where when adding new elements to the DOM after it's originally loaded, you need to read ajax:success higher up the DOM.
Thank you to those who provided input.
are you using turbo links? I think best in place binds to document ready which acts funky if you are using turbo links. If so, remove it from your application.html.erb and application.js file and try again.
I have a page that lets one create records - if the validations aren't satisfied, it redirects to the same page and shows an error message. Here's that snip from the controller:
def create
#signature = Signature.new(signature_params)
if #signature.save
redirect_to "/thanks"
else
redirect_to :back, :notice => error_messages(#signature)
end
end
The trouble is, this is resulting in a full page refresh - so the error message isn't visible because the input form is placed under the fold of the page. I can place it at the top of the page, of course, but is there a way to show the message without reloading the page? Thanks.
OK, so here's what I've settled on:
1) I'm handling validation on the client side with HTML5 "required" attributes - they were created for this explicit purpose and no other gems or plugins are needed. They are supported in all major browsers. Details in this article.
2) I've moved the error messages to the top of the page to handle the case in which a user either is on an old or mobile browser or has JavaScript disabled. Error messages must work with a complete request-response cycle (even if this means re-loading the page) before they work with anything else - this is the unobtrusive JavaScript approach.
3) For the AJAX version, I'm going to be using remote: => true on the form element as explained in the Rails guides. I might be making this open source once I'm done with the callback part of it, and will post a link here.
Obviously, handling errors with flash is the most uniform & DRY way to show the user what's going on, but if you're willing to think outside the box, you'll be able to use Ajax to accomplish a similar job by just handling the errors yourself:
Code Example
#app/controllers/signatures_controller.rb
def create
#signature = Signature.new(signature_params)
if #signature.save
#success = "true"
end
respond_to do |format|
format.js { #errors = error_messages(#signature) }
format.html {
if #success.defined?
redirect_to "/thanks"
else
redirect_to :back, :notice => error_messages(#signature)
end
}
end
end
#app/views/signatures/create.js.erb
<% unless #success.defined? %>
alert(<%=j #errors.inspect() %>)
<% end %>
#app/assets/javascripts/signatures.js
$(document).on("submit", "#signature_form", function() {
$.ajax({
url: "/signatures"
type: "POST"
data: $(this).parent().serialize(); //serialize the form (not the button)
error: function() {
alert("Sorry, there was an error!");
}
});
});
You'd actually be better using JSON for this. If you like the idea, I can refactor it to include JSON for you!
On my site I have a simple model called Feed.
I want to make a link/button that will pull the Feed record with id=5 (for example) using AJAX.
The record that has been pulled should be displayed in a partial.
How can I do that ?
Thanks,
Oded
If you use jQuery, you could do sth like this:
In your controller you must respond to ajax request using the respond_to :js. Then you could either render directyl javascript which will be executed on your site, or the way I suggest you, to render json and parse it on the client side.
class YourController < ApplicationController
def index
#model = YourModel.all
respond_to do |format|
format.html
format.json {
render :json => #model.to_json
}
end
end
On the client side, just bind a click handler and then fetch the data using the path to your controller:
$("#your_link_id").click(function() {
$.getJSON('/path_to_your_controller', function(data) {
console.log(data);
});
}
The code is not tested, but it should work in that way.
Note: the console.log works with firefox but not with safari, try using firebug for console output.
Kind of long for a SO answer, but this should get you going:
http://www.tutorialspoint.com/ruby-on-rails-2.1/rails-and-ajax.htm
That's where I got started with AJAX on RAILS
I saw this code in a Rails controller:
respond_to do |format|
format.js {}
end
I've seen this for XML and HTML formats but not for Javascript.
Is this the way you specify a return format if you use for REST, like if you use replace_html or remote_form_for? I know RJS templates return compiled Javascript so I'm thinking maybe this is where this code might kick in.
If you put code inside the hash symbols(format.js {}), is that what gets send back as javascript to the browser?
It is used when an AJAX request is sent from the browser to a controller. The controller can respond with a script (which is generated by ruby statements in the view) which will be executed on the client.
Rails does a little magic on figuring out what 'template' to send out
in controller:
def foo
end
in view: (app/views/controller/) you can have
foo.html.erb (usual, html template)
foo.rjs (javascript template)
rails will send out the right template back to the browser, HTML for regular requets and RSJ for Ajax requests. You might want to put in javascript code like 'page.replace_html' ..etc in your RJS template. This way, you keep the controller clear of view code.
yuo can always just add the format to the url and see what it responds, /something.js would respond using the format.js code, if you want to use it, you can do the following to avoid rendering your entire layout:
format.js { render :layout => false, :text => #models.to_json }
that would respond with a json string
format.js { render :layout => false }
would require a template called [action].js.erb