Topic: Pass result of a javascript function as a to a remote function param

Hi! I am pretty new to Rails and I got stuck here... I have googled for some hours but could find nothing.

I have a view with two selects (combo boxes) which show Books. Then I have two buttons to move a book from one of these combo boxes to the other.

Something like this:

<%= select_tag("normal_books",
     options_from_collection_for_select(@normal_books, 'id', 'title'),
     {:multiple => true}  ) %>
<%= select_tag("special_books",
     options_from_collection_for_select(@special_books, 'id', 'title'),
     {:multiple => true}  ) %>

<%= button_to 'Make special', :url => {:action => 'make_special'}, :remote => true %>
<%= button_to 'Make normal', :url => {:action => 'make_normal'}, :remote => true %>

Now, what I want to do is to pass the selected book or books from one list to the remote function "make_special" or "make_normal" called in the buttons.
I haven't found how to do it. I do not know how to pass something "dynamic"... i.e. the selected books in the combo boxes.

I implemented some javascript functions that I do not know how to call:

<script>
function chosenNormalBooks()
{
  return chosenBooks.selected_index  ## I also tried chosenBooks.value.... though it doesn't matter since they never get called
}
</script>

I tried passing parameters to the button in the following ways:

<%= button_to 'Make special', :url => {:action => 'make_special', :book => chosenNormalBooks()}, :remote => true %>
<%= button_to 'Make special', :url => {:action => 'make_special'}, :book => chosenNormalBooks(), :remote => true %>
<%= button_to 'Make special', :url => {:action => 'make_special'}, :book => escape_javascript(chosenNormalBooks()), :remote => true %>
<%= button_to 'Make special', :url => {:action => 'make_special'}, :book => "chosenNormalBooks()", :remote => true %>
<%= button_to 'Make special', :url => {:action => 'make_special'}, :with => "'book = + $('normalBooks').value()", :remote => true %>

but with no sucess in any of them sad

I am using Rails 3.1.3, JQuery, in an Ubuntu system and browsing with Chrome.

Thanks a lot in advance!

Carlos

Last edited by carlosgarciaq (2011-12-12 22:49:35)

Re: Pass result of a javascript function as a to a remote function param

Bind an Ajax call to the select element like this:

$(function($) {
    $("#normal_books").change(function() {
        $.ajax({url: "/make_normal/" + this.value,
        dataType: 'script'})
    });
});
Joe got a job, on the day shift, at the Utility Muffin Research Kitchen, arrogantly twisting the sterile canvas snout of a fully charged icing anointment utensil.

Re: Pass result of a javascript function as a to a remote function param

Thanks for your reply!

I saw this solution googling but it is not exactly what I want.

I want to be able to select books without moving them from one container (combo box) to the other. Only when the button is pressed should the books be moved from one list to the other.

In fact, I didn't explain everything: I have 3 combo-boxes, and 4 buttons to move them from one list to another. This means that first I select the book, and then I decide where to move it (or them) depending on which button I press.

Thanks anyway!

Carlos

Last edited by carlosgarciaq (2011-12-13 14:23:34)

Re: Pass result of a javascript function as a to a remote function param

That would take a bit more javascript,  but it's basically a JavaScript problem.

You'd have to bind a change event to the button  that reads the multiple values of the combo box,  and packages them up in an Ajax request.

It's doable,  you'd just have to invent your own 'packaging scheme' for sending over the multiple selected items in the Ajax call,  and the deciphering scheme in the controller action.   The hardest part is reading out the multiple selected values in from query,  and constructing a hash or whatever to ship them over. 

If you want to make things a bit easier,  you may want to try query UI.  You could do this with drag and drop, eliminate the need for buttons altogether,  just drag stuff from one list and drop it on the other!

Joe got a job, on the day shift, at the Utility Muffin Research Kitchen, arrogantly twisting the sterile canvas snout of a fully charged icing anointment utensil.

Re: Pass result of a javascript function as a to a remote function param

Thanks again!

Yeap, my next step is doing it with drag and drop. But I would like to have the buttons too... I explain why later.

I was stuck because I wanted to do it with the button_to helper, but it was as easy as using the click javascript event of a button.
So my solution now is:

<%= select_tag("normal_books",
     options_from_collection_for_select(@normal_books, 'id', 'title'),
     {:multiple => true}  ) %>
<%= select_tag("special_books",
     options_from_collection_for_select(@special_books, 'id', 'title'),
     {:multiple => true}  ) %>
<input type=button value='Make special' onclick='make_special()'>
<input type=button value='Make normal' onclick='make_normal()'>
<script>
function selected_elements(select)
{
  var sel = jQuery(select + " option");
  var elements = [];
  for (var i=0;i<sel.length;i++)
  {
    if (sel[ i ].selected)
    {
      elements.push(sel[ i ].value)
    }
  }
  return elements
}


function make_special()
{
  var selected_book_ids=selected_elements("#normal_books");
  if (selected_books.length > 0)
  {
    $.ajax({
      url: "/books/make_normal",
      type: 'POST',
      data: {selected_book_ids : selected_book_ids},
      dataType: 'script'
    });
  }
}

function make_normal() {...you can imagine...}
</script>

books_controller.rb

def make_special
  selected_book_ids = params['selected_book_ids']
  @selected_books = selected_book_ids.each do |b|
      book = Book.find b
      book.is_special = true
      book.save
      book
   end
end

make_special.js.erb

jQuery("#normal_books option:selected").remove();
<% @selected_books.each do |b| %>
jQuery("#special_books").append('<option value="<%=b.id%>"><%=b.title%></option>');
<% end %>

Ok, this works.... but it is not unobstrusive javascript at all.
If I wanted to do it UJS I guess I need the buttons both to work with JS and without it so I would need to make them work (as well) in a non-ajax way.I would do a form with a multiple select for normal books with one or more submit buttons. It would be a "special" form because:
   1) because there may be multiple books selected to be sent with the POST. I guess this can be handled without any problem with RoR. I would say the controller method would treat receive it as an array straight-forward.
   2) because the form has multiple submit buttons (remember I want to be able to send a book to one or another receiving select (combobox) element). I think this can be handled as well WITHOUT any JS (the reason for all this). But I am not so sure about it.

Then, there would be this overriding of the buttons inside the <script></script> that would call the ajax version that I already wrote on top (more or less), but using the "preventDefault" function.

I am just thinking loud, sorry for so much basic stuff being said. But if you could give me confirmation that I am as well thinking good it would help my learning.

Thanks!!

Carlos

Last edited by carlosgarciaq (2011-12-18 15:06:17)

Re: Pass result of a javascript function as a to a remote function param

To be honest,  I develop for a very limited audience,  I don't worry about having to support browsers without JavaScript.   UJS to me is just staying current with Rails 3.

So I can't give a real informed answer,  but you sound like you're on the right track.

Joe got a job, on the day shift, at the Utility Muffin Research Kitchen, arrogantly twisting the sterile canvas snout of a fully charged icing anointment utensil.

Re: Pass result of a javascript function as a to a remote function param

Thanks Brad, it is good feedback anyway.