page.insert_html not rendering partial correctly - ruby-on-rails

The following is in the text_field.
= f.text_field :title, :size => 50, :onchange => remote_function(:update => :suggestions, :url => {:action => :display_question_search_results})
The following is in display_questions_search_results.rjs.
page.insert_html :bottom, 'suggestions', :partial => 'suggestions'
Whenever the user types, I'd like to search the database for any tuples that match the keywords in the text field. Then, display those results. But, at the moment, _suggestions.haml only contains the word "suggestions!!".
But, instead of seeing "suggestions!!" in the suggestions div tag, I get:
try { Element.insert("suggestions", { bottom: "suggestions!!" }); } catch (e) { alert('RJS error:\n\n' + e.toString()); alert('Element.insert(\"suggestions\", { bottom: \"suggestions!!\" });'); throw e }
I've been trying to find out why this is being done, but the previously asked questions I found seem more complicated than what I'm doing...

If you specify element to update, it is assumed that your action will return html (not rjs/javascript), that will replace contents of specified element.
So, if you need to replace contents of :suggestions, just render partial in your controller:
render :partial => 'suggestions'
But if you need to add contents to this element, not to replace, remove :update => :suggestions from your view code:
= f.text_field :title, :size => 50, :onchange => remote_function(:url => {:action => :display_question_search_results})
And leave controller code as is:
page.insert_html :bottom, 'suggestions', :partial => 'suggestions'

Related

Rendering a partial N times instead of for each item in an array

I have a set of attributes that belong to a product, e.g. :name, :smalls, :mediums, :larges, :price, etc.
Right :smalls, :mediums, and :larges are arrays of strings:
#products = [
{ :id => 1,
:name => 'Product 1',
:description => 'description goes here',
:smalls => ['S'],
:mediums => ['M','M'],
:larges => ['L',],
:price => 50.0,
:names_and_numbers => 'optional'
}
]
The number of strings in each array determines the number of times the corresponding partial is rendered:
<div id="small-field-set">
<% product[:smalls].each do |small| %>
<%= render :partial => 'small', :locals => { :product => product, :small => small } %>
<% end %>
</div>
<div id="medium-field-set">
<% product[:mediums].each do |medium| %>
<%= render :partial => 'medium', :locals => { :product => product, :medium => medium } %>
<% end %>
</div>
<div id="large-field-set">
<% product[:larges].each do |large| %>
<%= render :partial => 'large', :locals => { :product => product, :large => large } %>
<% end %>
</div>
How can I have a number, rather than the size the array, determine how many times the partials is rendered?
I tried doing this:
{ ...
:smalls => [1],
:mediums => [2],
:larges => [1],
...
}
But that did not work.
When you do this...
{ ...
:smalls => [1],
...
}
...you still have an array: [1] is an array with one element, the integer 1 (just like [1, 2] is an array with two elements) . So first, you want to get rid of the arrays:
{ ...
:smalls => 1,
:mediums => 2,
:larges => 1,
...
}
For your view, when you use each you're saying, "do this one time for each item in the array." Since you now have a number, not an array, you can use times which, just like it sounds, means "do this N times":
<div id="small-field-set">
<% product[:smalls].times do %>
<%= render :partial => 'small', :locals => { :product => product, :small => "S" } %>
<% end %>
</div>
P.S. I'm not sure what the purpose of :small in the :locals hash is. Since your partial is called 'small' I'm guessing you don't need this, or can easily change your partial to get rid of it.
Why the array?
:smalls => 1,
Then
<% product[:smalls].times %>
<%= render :partial => 'small', :locals => {:product => product } %>
<% end %>

Rails AJAX select box

I am trying to have an AJAX event for a <select> box that will do some action when the selection changes. The select box is embedded inside inside a table's <td> tags
<td>
<%= form_tag '', { :id => 'test_form' } do %>
<select name='repo' value="<%= session[:repo] %>" >
<option></option>
<%#repos.sort! { |a,b| a.repo <=> b.repo }
#repos.each do |r| %>
<option <%= session[:repo]==r.repo ? "selected='repo'" : '' %>>
<%=URI.escape(r.repo)%>
</option>
<% end %>
</select>
<% end %>
<%= observe_form( 'test_form', :frequency => 2,
:update => 'update_results',
:url => {:action => :update_report, :page => 0, :update => 1 },
:loading => "$('res_spin').show()", :complete => "$('res_spin').hide()" ) %>
</td>
I have embedded the select box in a form and the observe_form method to listen for a selection change. My controller function is update_report that will do something when the selection changes. For some reason, when the selection changes, the controller function is not getting called at all.
Turned on "Firebug" and seeing this error a lot of times
$(form) is null
var elements = $(form).getElementsByTagName('*'),
Try observe_field (as discussed here):
<%= observe_field(:state, :url => { :action => :update_report, :page => 0, :update => 1 },
:update => :update_results,
:with => 'repo'
) %>

show/hide map, starting with a hidden map (display: none)

I haven't been able to load my page with a hidden map that I can then Show clicking on :toggle_map_button
In my view a Show/Hide button and a map:
<%= link_to_remote "Hide Map", :url =>{:action => :toggle_map}, :method => :get, :loading => visual_effect(:toggle_slide, "marketplace_map", :duration => 1, :queue => 'front'), :html => {:id => "toggle_map_button", :class => "toggle_map_button"} %>
<%= gmaps(:map_options => {:detect_location => true, :center_on_user => true, :zoom => 6, :id => "marketplace_map" }, :markers => { "data" => #json }) %>
In my CSS file:
#maketplace_map
{
width: 100%;
height: 400px;
display: none; <= this doesn't get to be set (when I check in HTML code with Bugzilla)
}
In my RJS file upon action :toggle_map:
page << "document.getElementById('toggle_map_button').innerHTML =(document.getElementById('toggle_map_button').innerHTML == 'Show Map' ? 'Hide Map' : 'Show Map')"
page.flash_msg(:notice_box, flash[:notice]) if flash[:notice]
page.flash_msg(:error_box, flash[:error]) if flash[:error]
flash.discard
The whole things works perfect when starting with a page showing the map. The toggle action does set display:none; correctly ...
The issue is comes when starting with a hidden map and be able to click and slide it down.
Any ideas?
Cheers,
Joel
Look bit closer at the html generated, I bet it's looking like:
<div class="map_container">
<div id="marketplace_map" class="gmaps4rails_map"></div>
</div>
so the adequate CSS lever is the map_container class. Put display:none on it.
since visual_effect seems to need an id, two options:
override the gmaps4rails partial
wrap the gmaps helper in a div: <div id="foo"> <%= gmaps(bar) %> </div>
I've got another solution for you, just tested.
You were right saying the map is small when hidden the visible.
so add an option to your helper: <%= gmaps(whatever, :last_map => false)%>
This will not create the map, only load it's objects.
Then add some javascript (I use jQuery but you've got the idea):
<script>
var createMap = true;
$(function(){
$("#click_me").click(function(){
if (counter == true)
{
Gmaps.loadMaps(); //this will create the map
counter = false;
}
$(".map_container").toggle(); // this hides and shows
});
});
</script>
resolved it thx to #apneadiving suggestion
added option:
:complete => 'Gmaps.loadMaps();' to visual_effect
In the view:
<%= link_to_remote "Show Map",
:url =>{:action => :toggle_map},
:method => :get,
:loading => visual_effect(:toggle_slide, "map", :duration => 1, :queue => 'front'),
:complete => 'Gmaps.loadMaps();',
:html => {:id => "toggle_map_button", :class => "toggle_map_button"} %>
<div id="map" style="display:none;" >
<%= gmaps(:map_options => {:detect_location => true, :center_on_user => true, :zoom => 6, :id => "marketplace_map", :last_map => false }, :markers => { "data" => #json }) %>
</div>

How to disable Rails submit buttons alongside Prototype helpers & RJS?

I'm trying to follow this post How can I unobtrusively disable submit buttons with Javascript and Prototype? but I can't get it to work. The form triggers an RJS function, so I need to keep the helpers' onclick events intact. The RJS returns/reloads the same forms along with two new texts. I'm really confused. Here is my rails code for the forms:
.span-20#comparison
/ new comparison . . .
/ voting forms (also reloaded)
.span-4.prepend-3.append-6
- form_remote_tag :action => url_for(:controller => :comparisons), :method => :post do
= hidden_field_tag :poem1_id, poems[:a].id
= hidden_field_tag :poem2_id, poems[:b].id
= hidden_field_tag :response, 1
= submit_tag "Vote for me", :disabled => false, :disable_with => 'Vote for me', :class => "compare"
.span-4.append-3.last
- form_remote_tag :action => url_for(:controller => :comparisons), :method => :post do
= hidden_field_tag :poem1_id, poems[:a].id
= hidden_field_tag :poem2_id, poems[:b].id
= hidden_field_tag :response, 2
= submit_tag "Vote for me", :disable_with => 'Vote for me', :class => "compare"
.span-4.prepend-8.append-8.prepend-top.last
- form_remote_tag :action => url_for(:controller => :comparisons), :method => :post do
= hidden_field_tag :poem1_id, poems[:a].id
= hidden_field_tag :poem2_id, poems[:b].id
= hidden_field_tag :response, 'draw'
= submit_tag "Declare Draw", :disable_with => 'Declare Draw', :class => "compare"
RJS
page.replace_html :comparison, :partial => 'poems', :object => #poems
page.insert_html :top, :previous, :partial => 'comparison', :object => #comparison
page << "Effect.ScrollTo($('top'));"
Here's one way you could do it using Prototype:
<script type="text/javascript">
document.observe("dom:loaded" function() {
$$("input .compare").each(function(submit) {
submit.observe("click", function() {
submit = true;
});
});
});
</script>
This adds an onclick event handler to every input element with a compare CSS class (i.e. your submit buttons) when the DOM is loaded. The onclick event handlers disables each button when it's clicked. Note that adding event handlers using Prototype this way does not replace any existing event handlers on the elements.

rails how to call another controller in link_to_remote

how to call a different controller's action using link_to_remote
:url => {:controller => "Posts", :action => "update"} doesn't work
the method:
link_to_remote(name, options = {}, html_options = nil)
passing in a hash like:
link_to_remote "hug kittens", { :url => { :controller => 'kittens', :action => 'show' } }
as the second argument (options) works. verified.
the result:
<a onclick="new Ajax.Request('/kittens/hug', {asynchronous:true, evalScripts:true, parameters:'authenticity_token=' + encodeURIComponent('/BdZwHdC/QqtBJsdCU+cCHxabHj/QHUT6i8ggbr5CtY=')}); return false;" href="#">hug kittens</a>
The problem with your implementation might be, that there is no "real" update-url (except you created one by hand). Please have a look at the url of your edit-form. It's actually a post-request to "posts/:post_id".
<%= link_to_remote "Save", :url=>{:controller => "Posts", :action => "update"}, :update=>"div_id" %>

Resources