How can I update a div value using Ajax but calling a function on the OnChange?

Hey guys,

I'm trying to update a div with a result coming from a request to the
database.

So I have created this method on the controller

  def retrieve_part_price
    @price = Part.find(params[:id])
    respond_to do |format|
      format.html { redirect_to(items_path)}
      format.js { render :nothing => true }
    end
  end

and added it to the routes properly, but I don't know how should I
call it from my view side to bring the value using Ajax.

any advice? blog post?

Thank you.

Kleber Shimabuku wrote in post #1015666:

any advice? blog post?

This works for me:

<h1>Users#new</h1>
<p>Find me in app/views/users/new.html.erb</p>

<%= link_to "Click me",
            {:controller => 'users', :action => 'get_info'},
            :remote => true %>

<div id="update_me">Hello</div>
<div>world</div>

You can make your js more general by doing this:

<h1>Users#new</h1>
<p>Find me in app/views/users/new.html.erb</p>

<%= link_to "Click me",
          {:controller => 'users',
           :action => 'get_info',
           :my_target => 'update_me'},

           :remote => true %>

<div id="update_me">Hello</div>
<div>world</div>

Thank you guys, but as I said in the topic, I looking how to perform
this on event OnChange of an <select>

Just updating:

I have this on a partial:

<p class="fields">
  <%= f.collection_select(:part_id, @parts, :id, :title, { :prompt =>
true } , { :onchange => "load_part_price_select(this.id,
this.options[this.selectedIndex].value);" } ) %>
  <span class='part_price'> _ _ _ _ </span>
  <%= f.hidden_field :_destroy %>
  <%= link_to_remove_fields "remove", f %>
</p>

and the relative function on application.js file:

function load_part_price_select(id, value) {
  alert(id);
  alert(value);
  $('#' + id ).live('change',function() {
      $.ajax({
      url: value + '/retrieve_part_price/',
      success: function(responseData) {
        alert('test');
      }
    });
  });
};

For now, I have to figure out a question about routes

I've created the right method on my ItemsController:

  def retrieve_part_price
    @price = Part.find(params[:id])
  end

and configured the routed as:

resources :items do
  get 'retrieve_part_price', :on => :member
end

but the development log shows me an error:

<!DOCTYPE html>
<html>
<head>
  <title><%= @title %></title>
  <%= csrf_meta_tag %>
  <%= javascript_include_tag :defaults %>

<script type="text/javascript">
    function update_info() {

        new Ajax.Updater( 'target_div',
                          '/users/get_info',
                          {
                            method: 'get',
                            parameters: {select_choice: $F("my_select")}
                          }
                        );

    }

    document.observe('dom:loaded', function() {
          $("my_select").observe('change', update_info)
      });
</script>

</head>
<body>

  <%= yield %>

</body>
</html>

Hi everyone,

Thank you all for the help. I pasted the final code on the pastebin so
if someone else needs it someday it will be available for consulting.

http://pastebin.com/E7dpHRhs

and the form

<p class="fields">
  <%= f.collection_select(:part_id, @parts, :id, :title, { :prompt =>
true } , { :onchange => "load_part_price_select(this.id,
this.options[this.selectedIndex].value);" } ) %>
  <%= f.label(:part_id, "Price: ") %>
  <span class="price"></span>
  <%= f.hidden_field :_destroy %>
  <%= link_to_remove_fields "remove", f %>
</p>

Kleber Shimabuku wrote in post #1015905:

and the form

<p class="fields">
  <%= f.collection_select(:part_id, @parts, :id, :title, { :prompt =>
true } , { :onchange => "load_part_price_select(this.id,
this.options[this.selectedIndex].value);" } ) %>
  <%= f.label(:part_id, "Price: ") %>
  <span class="price"></span>
  <%= f.hidden_field :_destroy %>
  <%= link_to_remove_fields "remove", f %>
</p>

js shouldn't be in your html, i.e. this:

{ :onchange => "load_part_price_select(this.id,

this.options[this.selectedIndex].value);"

should be done up in the <head> section of your html. In order to do
that, you have to put your js inside a function that executes after the
page has loaded.

now with rails 3.1 doesn't all the java code go in a *.js.coffee file
inside the app/assets/javascripts/ ?
or do we write it on the corresponding view directly?

@7stud,

the "onchange" behavior make a function call, that's right, and this
function (load_part_price_select() ) belongs to a js file, in this
case I did put it on the application.js file.

this is actually working for me.

@Filippos,

I haven't installed rails 3.1 yet, still on 3.0.9 for now, so I can't
tell you that, sorry.

Kleber Shimabuku wrote in post #1016065:

@7stud,

the "onchange" behavior make a function call, that's right, and this
function (load_part_price_select() ) belongs to a js file, in this
case I did put it on the application.js file.

Yeah, but you put the js that calls the function in the html here:

<p class="fields">
  <%= f.collection_select(:part_id, @parts, :id, :title, { :prompt =>
true } , { :onchange => "load_part_price_select(this.id,
this.options[this.selectedIndex].value);" } ) %>
  <%= f.label(:part_id, "Price: ") %>

Doesn't that look like a bunch of chicken scratchings to you? You could
make it 'look' better with some spacing, but the point is: mixing html
and javascript is bad style. If you load that page in a browser and do a
View Source, and then look at the <select> tag, it will have an onchange
attribute.

Mixing html and js was considered bad style more than 7 years ago, and
it remains bad style today. In fact, Rails 3 was redesigned so that
when rails generates html pages, no js appears in the html pages. In
your case, you are writing your own js(using jQuery), and you just
foiled the rails teams hard work by explicitly writing your js in the
html. You should watch this:

http://railscasts.com/episodes/205-unobtrusive-javascript

this is actually working for me.

Yes. It's horrible style though. css, js, and html should all be in
separate files. If you examine the code I posted, this is what the html
looks like:

<h1>Users#new</h1>
<p>Find me in app/views/users/new.html.erb</p>

<div id="target_div">Hello world</div>

<select id="my_select">
  <option value="mars">mars</option>
  <option value="venus">venus</option>
</select>

See any js in there?? Okay, I used prototype. Here it is with jquery:

<h1>Users#new</h1>
<p>Find me in app/views/users/new.html.erb</p>

<div id="target_div">Hello world</div>

<%= form_for(@user) do |f|
    f.collection_select(
      :id,
      @users,
      :id,
      :email,
      { :prompt => true },
      {
        :id => "my_select",
        :class => "cool_effects"
      }
    )
end
%>

===app/views/layouts/application.html.erb:

<!DOCTYPE html>
<html>
<head>
  <title><%= @title %></title>
  <%= csrf_meta_tag %>
  <%=
  javascript_include_tag
"http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js",
                         "jquery.rails.js"
  %>
<script type="text/javascript">

  $(document).ready(function () {

      $("#my_select").change(
        function () {
          var choice = $(this).val();
                     //turn 'this', which is the select element,
                     //into a JQuery collection object, which
                     //has a val() method.

          var query_string = "select_val=" + choice + "&another_val=10";

          $("#target_div").load('users/get_info', query_string)
        }
      );

  });

</script>

</head>
<body>

  <%= yield %>

</body>
</html>

In this code:

function load_part_price_select(id, value) {
        // alert(id);
        // alert(value);
        $('#' + id ).live('change',function() {
            $.ajax({
                  url: '/parts/' + value + '/price',
                  type: 'get',
                  context: this,
                  dataType: 'script',
                  success: function(responseData) {
                    // alert('success: ' + responseData);
                    $(this).nextAll("span.price:first").html(responseData);
                  }
                });
        });
};

...why do you have:

dataType: 'script',

I doubt your action is responding to the ajax request by sending a
string with js code in it back to your page--because your action looks
like this:

  def retrieve_part_price
    @price = Part.find(params[:id])
    respond_to do |format|
      format.html { redirect_to(items_path)}
      format.js { render :nothing => true }
    end
  end

It looks like you are trying to send a price back, so you should
specify:

  dataType: 'text'

But then I don't understand how your action returns anything because you
wrote this:

      format.js { render :nothing => true }

I think that should be render :text.