I have a project in Rails 3, with a partial _form_fields.html.erb that is rendered to a page and contains a remote link:
<!-- a few form fields, then... -->
<%= link_to '+', new_my_controller_path, remote: true %>
This gets processed by a controller, and appends this same partial below itself.
The controller:
def new
respond_to do |format|
format.js
end
end
And the related js.erb file:
$('.field-wrapper').append("<%= escape_javascript(render(partial: 'form_fields', layout: false)) %>")
All pretty standard, and the link loaded with the page works as expected, rendering the fields.
However, and here is my problem, when clicking this link on the newly rendered content, it submits as a regular link, ignoring remote: true.
Does anyone know the solution to this? I can't be the first person to have faced this, though haven't been able to find a solution - duplicates happily accepted if anyone can find one.
Thanks in advance.
Found the solution to this after a little debugging.
Looking at the terminal output when clicking the link, I noticed sometimes it would attempt to submit via JS, quickly followed by HTML; others, it would appear just to submit via HTML.
This suggested a race occuring between the default behaviour and that resulting from using remote: true.
The solution was to call e.preventDefault() on the element's click handler:
$('.my-element').click(function(e) { e.preventDefault(); })
Not ideal, and I presume fixed in newer Rails versions, though provides a little closure here :)
Related
I've been trying to solve the following challenge all day without any luck.
When going through forum posts I came across jQuery and AJAX which are both new concepts to me and which I'd rather skip for now, if possible.
I've got a partial, "navbar-left", which shows a list of all bank accounts in my model Account.
When the user clicks on one of the items in the list, all transactions of that account should be shown in the same page at the right. The partial below links to a new page which is not how I'd like it.
The navbar-partial:
<ul class="nav nav-pills nav-stacked">
<% #accounts.each do |account| %>
<li role="presentation"><%= link_to account.account_holder, account_mutations_path(account.id) %></li>
<% end %>
</ul>
Any tips on how to get this fixed is much appreciated!
The page with the navbar at the left
The mutations in a separate page instead of a partial
Either you're sending viewers to a new page, or dynamically loading content within their current page.
If the latter, then the only solution is AJAX.
Luckily, Ruby on Rails makes transitioning from one to the other very easy.
Here is a gist of how it works:
<%= link_to account.account_holder, account_mutations_path(account.id), remote: true %>
This was pointing back to some page previously (e.g. action.html.erb).
Because of remote: true, it's going to be sending JS directly to the browser instead of a new HTML page (e.g. action.js.erb in the same view folder and same action name).
Here we can control the behavior we want by rendering a partial using ERB and using JS to change the HTML content of some part of the page:
// action.js.erb
$('#some_element').html('<%= j render "partial" %>')
Which will insert the HTML of the partial directly into the JQuery that changes the content dynamically.
Where j is a shorthand for escape_javascript.
Without escaping, the Ruby output is interpreted as file output and newlines would break your JS.
Example JS output without escaping:
// Bad
$('#some_element').html('<span>Content</span>
<span>More Content</span>')
Example with escaping:
// Good
$('#some_element').html('<span>Content</span>\n<span>More Content</span>')
http://guides.rubyonrails.org/working_with_javascript_in_rails.html
https://launchschool.com/blog/the-detailed-guide-on-how-ajax-works-with-ruby-on-rails
There are more great examples online and even Railscasts.
Really AJAX is the best way to do this, and it's not as complicated as you might think. But if you really want to skip AJAX then your best approach is probably to load ALL transactions for all accounts, in different div's and then show or hide them based on which is clicked.
For a rudimentary introduction to this look at javascript tabs... you click on a tab, the appropriate information is shown.
http://www.w3schools.com/howto/howto_js_tabs.asp
You can do this very simply without ajax. The big difference would be - it's not the same page. One page would be the account#index (as you have now), the other page is the account#show page.
For the show page, use a very similar view as the index page, the left side would include the partial with one of the account li class="active" to highlight the account you are currently on. For the right side of the page, render the account mutations list items.
Apologies if this is asked before, but I can't find it...
I've got a page with a button bar that I need to update as the state of the page changes. The button bar is rendered with a partial.
The user can update the state with various AJAX actions on the page, and I'm doing various updates to the required elements. Mostly these are simple text strings, but the button bar is a bit more complex.
I'd have thought I should be able to do some variation on:
$('.button_bar').html( '<%= render :partial => 'buttons.html.erb' %>' );
But I'd need to somehow escape the render output for use in a string. While searching I came across render_to_string, but that just gives undefined method in my application.
I am not sure if I understand right, but
$('.button_bar').html( "<%= escape_javascript(render "buttons") %>" );
I am looking for a solution of adding a loading screen (or frame) while ajax is loading the data. All the other posts I can find online is about jQuery rather than Prototype... I would swear that I will use jQuery for my next project. But anyway the code is like this, using unobtrusive JS:
in search.js.erb:
$("main_content").update("<%= escape_javascript(render(:partial => "items")) %>");
for sure there is a search.html.erb with pretty similar content:
<%= render :partial => "items" %>
to add a loading screen, do I need to add something before this update function, or in the link_to statement, or somewhere else? I am totally new to this so please don't mind stupid questions. Thanks very much.
Update: I found something useful in the old link_to_remote function, which has a :loading and a :loaded tag to make the loading image or screen show up. However this has been totally not mentioned in the latest link_to of Rails 3. Is there any way to write it into the js file?
i m using rails 2.3.3 and web browser Firefox i have added ajax and java script and it is working too but i have to reload the page every time when i press Add to Cart button to show item additionn in the side bar it don’t show it without reloading.
anyone please help me how can it show item addition in side bar when i press Add to Cart button with out reloading the page?
If you haven't already done so, install Firebug for Firefox, for these reasons:
it'll tell you if you have a Javascript error.
it'll show you if your Ajax request is being received and its contents.
you can inspect your page elements such as the cart to see if it's set to be shown, if the ID is correct, etc. in a much faster way than browsing through the source.
and more (CSS, etc).
If you can't figure it out by looking at the Firebug console, and since you're following a tutorial, why don't you download the Depot source code and compare it with your own to see what you're doing wrong.
If you have the book, the complete source is listed at the end of the book. You can also download the source from here.
The standard ajax helper methods are link_to_remote, form_remote_tag, form_remote_for, button_for_remote. (I might have missed a few.) If you're not using one of them, you could be doing something wrong.
If you're using one of the helper methods with remote as part of the name, you might be missing the update option or the update option is pointed to the wrong html element.
For a form_remote_tag helper:
form_remote_tag(:url => {:controller => controller_name, :action => action_name, :id => id},
:update => element_to_update)
The element_to_update should be the html element's id that you're updating.
I've got a page where I'm dynamically adding elements to a from a series of select boxes. I'm using RJS to do this and it's working great. Now, these elements in the div are a series of that are accompanied by Delete buttons, in case the user wants to remove a textarea. Here's where I'm hitting a wall.
Here's the code that runs the Delete button. This is working well to my knowledge:
<%= link_to image_tag("/images/button_delete.gif", :alt=>"Delete"), :controller=>"report", :action=>"remove", :id=>#sentence.id %>
In my report controller, I've got this very simple method being called by the above code:
def remove
#sentence_id = params[:id]
end
Again, I think that's working. Now, when I activate this action by hitting the button, off we go to the RJS file, remove.rjs:
page.remove 'sentence_'+#sentence_id
And here's what I get in my browser, instead of a happily removed element!
try
{
Element.remove("sentence_63");
}
catch (e)
{
alert('RJS error:\n\n' + e.toString());
alert('Element.remove(\"sentence_63\");');
throw e;
}
My understanding is that this happens when there's no page in the current context. Online documentation on this is kind of thin.
Any help appreciated!
Cheers,
Aaron.
Try link to remote. That will build the ajax call for you and should remove the element from the page.
Then link_to_remote syntax is slightly different than the link_to syntax, so don't let that trip you up either.
Since your remove function doesn't seem to actually delete a record, if you just want to remove an HTML element from a page you can use link_to_function with the Prototype remove() method for Elements. In addition, if you've got a recent version of Rails (for example, 2.3.2) you can take advantage of the dom_id helper to auto generate the sentance_id ID attribute
<%= link_to_function(image_tag("button_delete.gif", :alt=>"Delete"), "$('#{dom_id(#sentence}').remove();" %>
An approach like this could help keep the number of methods down in your controller (unless you intend on doing something else in the controller)
Your Delete link is setup as a normal link, i.e.
<a href="/report/remove" id="sentence_63">
<img src="/images/button_delete.gif" alt="Delete" />
</a>
which triggers a normal HTTP request. Since your intent is to trigger an AJAX request, try PJ Davis' recommendation and use link_to_remote