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 S. wrote in post #1015666:

I’m trying to update a div …

This works for me in rails 3.0.9:

Users#new

Find me in app/views/users/new.html.erb

<%= link_to “Click me”,
{:controller => ‘users’, :action => ‘get_info’},
:remote => true %>

Hello
world

===

class UsersController < ApplicationController
def new
@title = “Sign up”
end

def get_info
@data = ‘world’
end

end

====

<%= @title %> <%= csrf_meta_tag %> <%= javascript_include_tag :defaults %>

<%= yield %>

===

TestApp::Application.routes.draw do

get “users/get_info”

===app/views/users/get_info.js.erb

$(“update_me”).update(“<%= @data %>”);

(which uses prototype)

any advice? blog post?

See: #205 Unobtrusive Javascript - RailsCasts

You can make your js more general by doing this:

Users#new

Find me in app/views/users/new.html.erb

<%= link_to “Click me”,
{:controller => ‘users’,
:action => ‘get_info’,
:my_target => ‘update_me’},

       :remote => true %>
Hello
world

===

class UsersController < ApplicationController
def new
@title = “Sign up”
end

def get_info
@target = params[:my_target]
@data = ‘world’
end

end

==app/views/users/get_info.js.erb

$("<%= @target %>").update("<%= @data %>");

Just updating:

I have this on a partial:

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

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:


Started GET “/items/29/8/retrieve_part_price/” for 127.0.0.1 at
2011-08-10 07:22:57 +0900

ActionController::RoutingError (No route matches “/items/29/8/
retrieve_part_price”):

Probably the best way would be something like “/items/29/
retrieve_part_price/8”

But how to make the route act this way?

On Aug 10, 6:54am, Kleber S. [email protected]

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

<%= @title %> <%= csrf_meta_tag %> <%= javascript_include_tag :defaults %>

<%= yield %>

===

Users#new

Find me in app/views/users/new.html.erb

Hello world
mars venus

===

class UsersController < ApplicationController
def new
@title = “Sign up”
end

def get_info
@choice = params[:select_choice]
@reply = “Hello #{@choice}”
render :text => @reply
end

end

Kleber S. wrote in post #1015905:

and the form

<%= 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: ") %> <%= f.hidden_field :_destroy %> <%= link_to_remove_fields "remove", f %>

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 section of your html. Note how ugly the
the html looks when the js is ‘inline’. Instead, you should
move the js up into the section(ideally you would link to a
separate file containing the js in the section). In order for
things to work correctly,
you have to put the js inside a function that executes after the
html page has loaded, like I did here:

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

The js in the section executes
before the tag is parsed by the browser, and therefore no html
elements in the exist when the js executes. That means you can’t
ask your js to search for html elements in the section–they
don’t exist.

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.

and the form

<%= 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: ") %> <%= f.hidden_field :_destroy %> <%= link_to_remove_fields "remove", f %>

@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.

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?

Kleber S. 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:

<%= 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 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:

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:

Users#new

Find me in app/views/users/new.html.erb

Hello world
mars venus

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

Users#new

Find me in app/views/users/new.html.erb

Hello world

<%= 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:

<%= @title %> <%= csrf_meta_tag %> <%= javascript_include_tag "http://ajax.googleapis.com/ajax/libs/jquery/1.6.2/jquery.min.js", "jquery.rails.js" %>

<%= yield %>

===

class UsersController < ApplicationController
def new
@user = User.new
@users = User.find(:all)
@title = “Sign up”
end

def get_info
choice = params[:select_val].to_i
other_data = params[:another_val].to_i
reply = “Hello #{choice + other_data}”
render :text => reply
end

end

===

As far as I can tell, I need the route:

resources :users

in order for collection_select to work–in addition to:

get ‘users/get_info’

for the ajax request.

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
js code back to your page–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. I don’t understand how your ajax
request ‘works’. It doesn’t do anything. You might want to read up on
render():