Rendering a completely new partial using jquery ajax - ruby-on-rails

I'm trying to write an AJAX call that renders a new partial when a particular item is selected from a drop down list. I have been searching for a solution all day with no luck :(
The only way I got it working was not using AJAX, but having a hidden div containing my second partial, and then showing it and hiding the other div when the appropriate option is selected from the drop down box. Yes this worked but I was looking for a cleaner solution.
I'm not looking for a direct answer, but if anyone has any resources that could point me in the right direction it would be greatly appreciated :)

How about adding a controller action that would render the view (so it's view would just render the partial), and then using jquery to place it:
$('#id-of-box').load("<%= some_action_path %>")

You should perform a remote AJAX call when the onchange event from your select element is being triggered, so on the page which contains your select element there should be something like this (inside a script):
$('#select_id').live('change',function(){
$.ajax({
url: 'url_bound_to_partial_renderer'
});
}
and on the action of the controller which responds to your url_to_fetch_result, you should write something like this:
# controller
# action bound to 'url_bound_to_partial_renderer' by routes.rb
def partial_renderer
...
end
#view (partial) _partial_renderer.js.erb
$('jquery_selector_path_to_container_element_of_your_partial').html("<%= escape_javascript render(:partial => 'my_partial') %>");
#view (partial) to be rendered inside container element: _my_partial.html.erb
<p>Here goes the content of the partial you want to be rendered on the container!</p>
Hope this will respond to your question.

Related

Kaminari with AJAX, unable to paginate

I've followed the AJAX Kaminari example here: https://github.com/amatsuda/kaminari_example/tree/ajax
I've successfully generated the partial and table. However, pressing the pages in the pagination does not update my table. In fact, upon pressing, the queries are the exact same data.
I found a similar problem, however the solution remains unanswered:
kaminari ajax pagination not updating the paginate
I can verify that I am using the #paginator element.
Some things I did do differently were instead of creating a separate js.erb file, I added
<script>
$('#paginator').html('<%= escape_javascript(paginate(#pending_requests, :remote => true).to_s) %>');
$('#requests').html('<%= escape_javascript render (#pending_requests) %>');
</script>
at the end of the of my html.erb file.
Also, in a view, I use an ajax request to select different data within the table. For example, I have a select_tag which upon selecting a user, the appropriate table is rendered using AJAX in the view. The table isn't a partial, it has its own view and method in the controller. At first I suspected that because of this, the table wasn't being updated. However, if I go to the table url, I am still unable to use pagination!
Edit: I am able to right-click the pagination links and open them to another tab. Clicking on them still doesn't do anything.
EDIT:
I wanted to add that I'm using Twitter Bootstrap. I noticed that if I set in my controller
format.html { render :layout => false }
Then I open one of the pagination links to another page, I can successfully paginate. I am using the Kaminari bootstrap theme however...
I didn't see a place to add a comment, so this is not a real answer.
Do only render the table with AJAX? Is the partial part of another page? Or is a stand alone view?
I had a similar problem (last post before your on the Kaminari tag page link where I had the option to render the table as a partial in a show view or as a separate page. that messed things up. I ended up, like you adding a script tag, but yours in not wrapped in a document ready function, so the page might not be fully loaded. Try.
<script type="text/javascript" charset="utf-8">
$(document).ready(function() {
$('#paginator').html('<%= escape_javascript(paginate(#pending_requests, :remote => true).to_s) %>');
$('#requests').html('<%= escape_javascript render (#pending_requests) %>');
})
</script>

Rails: What does it actually mean to "render a template"

I've become a bit confused about the idea of "rendering" a "template" due to the way an author speaks about it in a book I'm reading.
My original understanding of "rendering a template" was that it meant that Rails is providing the content that is viewed on the screen/presented to the viewer (in the way that a partial is rendered) but the book I'm reading seems to be using the concept of "rendering a template" to also mean something else. Let me explain in context
This book (rails 3 in action) sets up a page layout using the conventional layouts/application.html.erb file, and then it "yields" to different view pages, such as views/tickets/show.html.erb which adds more content to the screen. that's all straightforward..
Within this view views/tickets/show.html.erb, there is a rendering of a partial (which is also a straightforward concept).
<div id='tags'><%= render #ticket.tags %></div>
Now within this partial there is, using ajax, a call to a "remove" method in the "tags_controller.rb" which is designed to allow authorized users to remove a "tag" from a "ticket" in our mock project management application.
<% if can?(:tag, #ticket.project) || current_user.admin? %>
<%= link_to "x", remove_ticket_tag_path(#ticket, tag),
:remote => true,
:method => :delete,
:html => { :id => "delete-#{tag.name.parameterize}" } %>
<% end %>
Now here is the "remove" action in the tags controller (which disassociates the tag from the ticket in the database)...
def remove
#ticket = Ticket.find(params[:ticket_id])
if can?(:tag, #ticket.project) || current_user.admin?
#tag = Tag.find(params[:id])
#ticket.tags -= [#tag]
#ticket.save
end
end
end
At the end of this remove action, the author originally included render :nothing => true , but then he revised the action because, as he says, "you’re going to get it to render a template." Here's where I get confused
The template that he gets this action to render is "remove.js.erb", which only has one line of jquery inside it, whose purpose is to remove the "tag" from the page (i.e. the tag that the user sees on the screen) now that it has been disassociated from the ticket in the database.
$('#tag-<%= #tag.name.parameterize %>').remove();
When I read "rendering a template" I expect the application to be inserting content into the page, but the template rendered by the "remove" action in the controller only calls a jquery function that removes one element from the page.
If a "template" is "rendered", I'm expecting another template to be removed (in order to make room for the new template), or I'm expecting content to be "rendered" in the way that a partial is rendered. Can you clarify what is actually happening when a "template" is "rendered" in the situation with the jquery in this question? Is it actually putting a new page in front of the user (I expected some sort of physical page to be rendered)
You're nearly there! Rendering a template is indeed always about producing content, but for a slightly wider description of content. It could be a chunk of html, for example an ajax call to get new items might produce some html describing the new items, but it doesn't have to be.
A template might produce javascript as it does in your second example. Personally I am trying to avoid this and instead pass JSON back to the client and let the client side js perform the required work.
Another type of rendering you might perform is to produce some JSON. APIs will often do this, but you might also do this on a normal page. For example rather than rendering some javascript to delete tag x you might render the json
{ to_delete: "tag-123"}
and then have your jQuery success callback use that payload to know which element to remove from the DOM, by having this in your application.js file
$('a.delete_tag').live('ajax:success', function(data){
var selector = '#' + data.to_delete;
$(selector).remove()
}
(Assuming that your delete links had the class 'delete_tag')
Rendering JSON like this isn't really a template at all, since you'd usually do this via
render :json => {:to_delete => "tag-#{#tag.name.parameterize}"}
although I suppose you could use an erb template for this (I can't imagine why though).
My understanding is that js.erb is "rendered" by executing the javascript functions within it. Very often something like the below is done:
jQuery(document).ready(function() {
jQuery('#element').html('<%= escape_javascript(render pages/content) %>');
});
There's a really succinct overview of rendering at http://guides.rubyonrails.org/layouts_and_rendering.html that may help as it also goes into the details of the ActionController::Base#render method and what happens behind the scenes when you use render :nothing (for example). Render but can be used for files or inline code as well -- not just 'templates' in the traditional sense.

Rails - display results of index and show actions via ajax

I have a very simple Post resource with two actions, index and show. My template contains a sidebar with links to each previous post. I want the sidebar links to display their content (i.e. the results of the "show" action) via ajax
I know there are lots of excellent tuts that show you how to create a form that submits with ajax but this time I want to use it to display the contents of my index and show actions without page referesh
. Are there any decent tutorials out there that give tips on how to do this?
I reckon I need to create a show.js.erb file, and tell my index action to respond to js but I'm a little bit stuck getting any further. I don't quite know what to put in controller's show action or show.js.erb - it's a little difficult to visualise what I need to do
PS - using rails 3.0.7, jquery-1.5
Got this working, it was very simple in the end.
Step 1 - add :remote => true to links in sidebar
#application.html.haml
%nav#sidebar
- for post in #posts
= link_to post.title, post_path, :remote => true
%div#main
= yield
Step 2 - tell your controller to respond to JS on the show action
def show
#post = Post.find(params[:id])
#posts=Post.all # needed for sidebar, probably better to use a cell for this
respond_to do |format|
format.html # show.html.erb
format.js # show.js.erb
end
end
Step 3 - Create _post.html.haml
# _post.html.haml
%article.post
= sanitize post.body
Step 4 - Create show.js.erb and replace the html in the #main div with the contents of the _post partial (that we created in step 3)
# show.js.erb
$("#main").html("<%= escape_javascript(render #post) %>");
Now all the content is passed via ajax and it's working fine.
I don't have a full answer at hand, because I'm relatively new to this, too.
But, I would start by taking a look at JQuery's get() method. You should be able to use that to call the index or show method. Those methods should return the html that you want to display in the non-sidebar section of the page. You can use get()'s callback handler to place that HTML into the appropriate div on the page.
Sorry that this is a little vague, but if you play with this I bet you'll figure it out.

How can I create this dynamic form?

Imagine a dropdown with 3 options:A,B,C and a div with the id of myform.
When the user selects an option from the list, the div's content should be replaced by the form corresponding to the option. The thing is, the forms have nothing in common.
I was thinking of tackling this in the following way:
create a new controller FormCreator
create a new action build_form , which will take a type as a parameter (A/B/C)
create A.html.erb, B.html.erb and C.html.erb
depending on the type, I will render either A/B/C, with layout rendering disabled
use ajax to replace the content of the div with what the controller produced
Is there a better way of doing this?
Here's guideline how I would do it: When some option is selected, for example A, with AJAX GET AController#new as JSON and return form rendered by erb. Than $('#myForm').html(withResponse). Main idea is that on select.change event you hit correct resource controller new action and replace div content with it's response.
Not complete answer but I hope it will give you an idea
Why not just hide the forms and reveal/hide them upon select list selection? It doesn't matter which controller or action you render the forms/select list from but they should probably post to their own controller and render only the previously posted form on validation failure.
Use a javascript select to call your AJAX controller with :onchange => remote_function(...)
In your controller =>
def FormCreator
if params[:form] == 1
render :update do |page|
page.replace_html 'form_div', :partial => 'form_1'
#make a file with just the form called _form_1.erb, this is called a partial
#because the file name starts with '_'
#form_div is the id of the div that holds all 3 forms.
end
end
#repeat for all forms
end

Posting a form through popup in Rails

I have a model called Details, and two controller methods new and create. New method displays a form to create Details (in new.html.erb), which gets posted to the Create method that saves it. (when it succesffully saves, it it renders the new.html.erb file with the details.) This works as expected.
Now i want a separate page with a link to fill in these details. I want the click to do the intended work through a popup, example redbox. When you click on that link, a popup should show the form, whose submit should post the form, and if it is successfully done, then refresh the original page. If the post is unsaved, then the same form should show the errors. What do i need to do to make it work in Ror? I guess i need some stuff to go in new.js.rjs and maybe create.js.rjs, but i can't really figure out what to put in those files.
Redbox updates the page's dom to add a div at the end of it. So your form is a part of the main page.
So if you add a form tag in this redbox, all your page will be reloaded as there's only one.
So you add anywhere in your page (preferably at the end) :
<div id="redbox" style="display: none;">
<%= form_for #details do %>
# Whatever form fields you want here
<% end -%>
</div>
You do a link that'll open the redbox :
<%= link_to_redbox 'Open The Details Form', 'redbox' %>
This will display your redbox with your form.
And as it is the same page, not a new windows, when you'll validate your form, it'll reload the all of it.
I used a link_to_remote_redbox for this, which on clicking, fetches the form rendered by the new method call in a popup widnow. it submits to the create function and it is now working. actually i had previously made it work without ajax and i was having difficulty in making it work with ajax. the problem was solved once i made separate partials for ajax calls, and doing:
respond_to do |format|
format.js { render :template => 'detail/ajax_template'}
...
end
I provided different templates for both create and new method calls, used the :html => {:id => 'some-id'} in form and the :update => {:some-id} to replace the form with the message that it worked correctly.
So I didnt know that i needed separate templates for the different styles of forms, and that i needed to use the :update option to replace the form when i asked the above question.

Resources