Rails is rendering an empty partial from js.erb - ruby-on-rails

I'm trying to render a partial from a js.erb file but nothing is shown in the view.
There is an AJAX call that triggers the report_announcement action in the announcements_controller when a button is pressed.
reports.js
$.ajax({
type: "POST",
contentType: "application/json",
url: "/announcements/report_announcement.js",
data: json_data
});
reports/_report_content.html.erb
<div id="report_announcements_container"></div>
announcements_controller.rb
def report_announcement
#announcement = Announcement.new(announcement_params)
respond_to do |format|
if #announcement.save
format.js {}
end
end
end
announcements/report_announcement.js.erb
I know that announcements/report_announcement.js.erb is rendering ok because I can see the logging statement in the console and also in the development.log as well as the report_announcement object being logged to the console.
<% announcement_json = #announcement.to_json.html_safe %>
var report_announcement = <%= announcement_json %>;
console.log('report_announcement');
console.log(report_announcement);
// this is where something is not right I think
$("#report_announcements_container").html("<%= escape_javascript(render partial: 'announcements/report_announcements', locals: { announcement: #announcement }) %>");
console.log('inside announcements....');
announcements/report_announcements.html.erb
This is where I'm having an issue because the logging statement for the partial is shown however nothing from the partial is shown on the page. I see in the development.log that the page rendered but nothing is actually shown in the view. The partial is not showing on the page in the report_announcements_container div.
<h1>test</h1>
<%= announcement %>
<script>
console.log('inside partial...');
</script>

You're using the wrong content-type in your ajax call. Rails recognizes both application/javascript and text/javascript as the :js format.
Also when you request a js format you actually have to execute the returned javascript for anything to happen in the client.
$.ajax({
type: "POST",
contentType: "application/javascript",
url: "/announcements/report_announcement.js",
data: json_data
}).done(function(data){
jQuery.globalEval(data); // Yeah eval is evil.
});
If you have done any "real" ajax calls before this will seem completely backwards - thats because it is. js.erb is a poor mans ajax framework for the javascript impaired which consists of a bunch of routes and views that mutate the DOM in the client.
Manually creating calls for a js.erb template is just a silly excerise in masocism. If you really want to use it create a form and use it send the request instead so that you can just leverage the javascript handlers that rails provide:
<%= form_with(url: "/announcements/report_announcement", remote: true) do |f| %>
# ...
<% end %>

Related

Rails AJAX partial not rendering properly

I have:
<p id="click">Click here</p>
In contorller:
#details=Family.find_by(famid: params[:famid])
respond_to do |format|
format.html
format.json {render :json => #details}
end
and:
$('#click').on('click',function(){
$.ajax({
type: "GET",
data: 'famid='+id,
dataType: "json",
url: "/map",
success: function(data){
document.getElementById('myModal').innerHTML = data.famid
}
});
}
<div id="myModal"></div>
This works fine. The myModal div tag is populated by the correct famid value. But I just want to post the data to the controller via ajax and query the database and use the #details variable instead. So I tried:
$('#click').on('click',function(){
$.ajax({
type: "POST",
data: 'famid='+id,
dataType: "json", //do I need this? should it be html?
url: "/map"
});
}
Now I want to use the #details variable like:
<div id="#myModal"> <%= #details.famid %> </div>
How do I do that?
UPDATE: Ok I did the following things and everything works fine (thanks to #Rich & #NitinJ) except the partial. It's not rendered properly.
map.js.erb
$("#myModal").html("<%= escape_javascript(render(#details))%>");
_details.html.erb
<h3><%= #details.famid %></h3>
map.html.erb
<div id="myModal">
<%= render #details %>
</div>
Update:
Now the partial is rendered correctly in the browser console. I can see the #myModal div being populated correctly. But it's showing only in the browser console and not on map.html.erb page. What is wrong here?
Ajax
$('#click').on('click',function(){
$.ajax({
type: "POST",
data: {famid: id}, //you need to serialize your data
dataType: "json", //do I need this? should it be html?
url: "/map"
});
}
AJAX is quite simple - it sends a request on your behalf. The $.ajax function is from JQuery, so to get it right, you just need to pass the right arguments to it
Routes
#config/routes.rb
post "map", to: "your_controller#map"
Because you're sending a POST request (rather than GET), you'll need a route to handle the request. And since you're sending to /map, you need to ensure you're going to catch that request & send to the right controller
Controller
#app/controllers/your_controller.rb
def map
#details = Family.find_by(famid: params[:famid])
respond_to do |format|
format.html
format.json {render :json => #details}
end
end
Response
Because you're dealing with JSON, I believe you'll be best handling the response in the view directly, like this:
$('#click').on('click',function(){
$.ajax({
type: "POST",
data: {famid: id}, //you need to serialize your data
dataType: "json", //do I need this? should it be html?
url: "/map",
success: function(data) {
details = jQuery.parseJSON(data)
$('#modal_body').html(details.famid);
}
});
}
To my knowledge, JSON is meant to pass data succinctly (with as few moving parts as possible), and consequently, we always handle the JSON response from the Ajax request; rather than a separate file
You can use the jQuery.parseJSON function to handle this, creating an object you can then append to the page
Update
I believe your problem is you're using JSON
You can't load a rails .js file with JSON - you have to load .json.erb, or process in the front-end view. You may wish to change your request to standard JS:
#JS
$('#click').on('click',function(){
$.ajax({
type: "POST",
data: {famid: id},
url: "/map"
});
}
#Controller
def map
#details = Family.find_by(famid: params[:famid])
respond_to do |format|
format.js
format.html
end
end
#app/views/controller/map.js.erb
$("#myModal").html("<%=j render(#details) %>");
You have to create a js.erb template than render this template. Now you can access this variable in your *.js.erb template
alert("<%=#details.famid%>")
you can also update your text of p tag by
$("modal-body").text("<%=#details.famid%>")

How to use client side validation with remote => true rails 3.1

Normally we can use many ways to use ajax with validation like using validate plugin or using plain ajax(no rails ajax) like below
data using ajax requests
$.post("test.php", $("#testform").serialize());
In your situation it can be something like that.
$('#your_form').submit(function(event) {
event.preventDefault();
/* Email validation here.*/
$.ajax({
type: "POST",
url: $(this).attr('action'),
data: $(this).serialize(),
});
});
But, I wish to use client side validation with Real Rails ajax . Please help how to do this?
Maybe you'd like to use this gem
UPDATE 1:
Since you want to do this through ajax, validation can be handled through you controller.
# Let's assume your remote request hits index
def index
#object.create(params[:object])
respond_to do |format|
format.html # index.html.erb
format.js
end
end
Now, define an index.js.erb in the relevant views folder & render
<% if #object.new_record? %>
alert("Failed to upload record: <%= j #object.errors.full_messages.join(', ').html_safe %>");

How can I add content dynamically in rails?

I have controller with a page named list.html.erb
when a user clicks a link I want to append content dynamically to the page and execute javascript afterwards.
is it possible to have a method which renders a js.erb file and I put into this file the variables containing the content?
best phil
As described there: http://api.rubyonrails.org/classes/ActionView/Helpers/UrlHelper.html#method-i-link_to you need to use
link_to 'Something', 'somewhere', remote: true
Yes, of course. It may not be the best course of action, though.
If you're enhancing the functionality of the view through Javascript, it's probably better to keep the code in Javascript rather than Ruby-generated Javascript.
Make a simple HTML link that GETs the new content from a controller in the JSON format or even as an HTML snippet. Use something like $.ajax and its success callback function to append said response to the element in the page.
$.ajax({
url: "whatever/here",
type: "GET",
data_type: "json",
success: function(response) {
$("#element_in_question").append(response); //if HTML; if JSON, parse and build the HTML
},
error: function(xhr, status, message) {
//indicate failure somehow
}
});
You can include a partial in your list.html.erb and display the partial on changing some content on the page list.html.erb. For example considering your list.html.erb file, you can include the following in your page
<form_for :something, :remote => true, :method => get :url => {:action => "partial"} do |f| %>
//write your code here
<%=f.submit%> //here you can have :onchange in the form_for tag if you do not want a submit button
write a division for partial in your list page as below
<div id="partial">
</div>
write a partial.js.erb file like this:
$('#partial').html("<%=j render "partial" %>");
create a _partial.html.erb file with the content you want to add the list.html.erb dynamically.
in the controller, add the following code:
def partial
//write your code here
respond_to do |format|
format.js
end
This will display the added content in the div tag of your list page with div id "partial"

embed ruby in coffeescript? to render a partial on ajax success and append to body

My view has a link (remote: true) to the "new" action in the controller (HTTP "GET"), which responds with some data in JSON format...
I want to use AJAX and have my coffeescript file append a rendered partial on AJAX success...
here is the code:
$ ->
$('a').click (e) ->
e.preventDefault()
url = $(this).attr('href')
$.ajax
type: 'get'
url: url
dataType: 'json'
success: (json) ->
# I want to do something like this:
$('body').append(render :partial => "questionForm", :locals => {:q_id => json.q_id})
This is obviously not the correct syntax... is it possible to embed ruby into my js.coffee somehow? I've checked through everything else, and if I just do something like :
$('body').append(json.q_id)
it works - so the AJAX call and "new" action etc. all seem to be working.. Any ideas? Is it possible to do something like this?
If you're returning data from the server, then you probably want to use a client-side tempting system (handlebars, jquery-templates, eco) to take the json data and turn it into HTML.
If you want the server to render the HTML for you, then you can have the server render the HTML and use jquery to append it.
Something like:
<%= link_to "New Model", new_models_path, remote: true, id: "batman" %>
Then in your app/models/new.js.erb, you'd:
$("#batman").html("<%= escape_javascript(render partial: "models/form", locals: {model: #model})%>");

Creating a :remote=>true post using AJAX rather than rails

I've spent a day spinning my wheels trying to understand how Rails :remote=>true works. The question below seems complicated but I'm trying to understand this simple question with the information I provide:
How can I make an Ajax call that simply renders as JS without using :remote=>true?
From my understanding :remote=>true simply generates and handles an AJAX call:
My view looks like this:
opts in a very complicated way, creates a link with :remote => true. This is omitted for simplicity
.e_list
= opts.sort_link(:name)
= opts.sort_link(:description)
- e_list.each do |e|
.entry
= link_to(e.name, '#', class: 'select_e', data: {e_id: e.id})
= e.description
= paginate e_list, remote: true, params: {search:"j", com_id: com.id}
Gallery.js.erb
$('#com<%= #com.id %>').replaceWith('<%= escape_javascript render(partial: "shared/com", locals: {com: #com}) %>');
My Controller:
def gallery
if params[:com_id]
#com = #s.com.find(params[:com_id])
#com.filter = params
end
if c = #s.com.where(:_type => "Com").first
#current_e = c.entries(#user.app_id).first
#current_e.og_url = view_context.og_url(#current_e)
end
render :text => "foobar" if !#current_e
end
logs, after the user clicks on the pagination links or sort links (the key is those links have :remote => true)
Started GET "super long url" for 127.0.0.1 at 2012-05-04 16:08:42 -0700
Processing by CController#gallery as JS
SO I TRY TO RECREATE THIS WITH AJAX:
$('button.search').live 'click', (e) ->
search = $(e.target).attr('search-term')
success_callback = (results) ->
if results
console.log(results)
update_components(results[0].entry, '.entry')
else
$.ajax(
url: 'super long url that is exactly the same url as above!'
).done ->
return false
MY FAILED RESPONSE THAT DOES NOT RENDER AS JS, YET I THOUGHT :remote => true was simply an ajax call wtf?:
Started GET "super long url identical as the one that renders JS" for 127.0.0.1 at 2012-05-04 16:07:22 -0700
Processing by ContestController#gallery as */*
What is going on? How can I make an Ajax call that simply renders as JS without using :remote=>true?
Try
$.ajax({
url: 'your url',
dataType: 'script'
})
http://www.alfajango.com/blog/rails-3-remote-links-and-forms-data-type-with-jquery/
try
/screens/4fa02763dc1c82269c0001da/contest/gallery.js?app_row_id=5....
If you want the js from the response to execute in the browser you should need to do something like eval(response), but i'm just suggesting, I never done it and even know how to eval code of a string in javascript.
You could use jQuery to accomplish what you are trying to do:
/* your jquery file */
jQuery.ajaxSetup({
'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
})
...
$('#button').click(function() {
$.post('/controller/action', {
query_string1: value1
});
});

Resources