Topic: :onChange issue

I'm taking my first steps in JavaScript.

I adapted a line of code written by danger that I found elsewhere in the Forum, changing it to this:

Advert Format:    <%= select_tag :advertformat, options_for_select(["","mediumrectangle","verticalrectangle"]), :onChange => remote_function(:url => 'advertformat') %>

I have two rjs files (mediumrectangle.rjs and verticalrectangle.rjs) and I need the one that is selected to be loaded. What do I need to write in place of the last 'advertformat' in this line of code to make this happen?

Re: :onChange issue

Take a look at the HTML source which is generated by this line. You should see some Javascript in the onchange attribute. You'll basically need to replace the call to remote_function with the javascript which was generated:

:onchange => "...javascript here..."

This way you can customize it. You should see the URL in the javascript code (advertformat). You need to replace that with wherever you want it to go. You can call this.value in Javascript in that line to return the value of the selected menu. Sorry I can't provide code at the moment, if you want to paste the HTML source I may be able to hack something up.

That said, there may be a better way to do this. This is the only way I know though.

Railscasts - Free Ruby on Rails Screencasts

Re: :onChange issue

Thanks Ryan. I copied the HTML source (having swapped out "advertformat" for the name of one of my two rjs files), and it works like you said it would:

Advert Format:    <%= select_tag :advertformat, options_for_select(["","mediumrectangle","verticalrectangle"]), :onChange => "new Ajax.Request('mediumrectangle', {asynchronous:true, evalScripts:true})" %>

As you suggested, I now need to call 'this.value' in JavaScript in that line instead of 'mediumrectangle' so that the selected rjs file is loaded. I'm having no luck trying to work out how to do that: Can you tell me what that call looks like? Thanks again!

Re: :onChange issue

You need to insert the URL that you want to call in the Ajax.Request call. Right now it is set to "mediumrectangle".

:onChange => "new Ajax.Request('mediumrectangle', {asynchronous:true, evalScripts:true})"

You need the name of the controller followed by "this.value" which should return the selected action. For example:

:onChange => "new Ajax.Request('foo/' + this.value, {asynchronous:true, evalScripts:true})"

Of course replace "foo" with your controller name.

Railscasts - Free Ruby on Rails Screencasts

Re: :onChange issue

Yay--it worked! Thank you Ryan!

It might be because I have RESTful routes, but I had to delete the foo bit entirely, leaving this:

:onChange => "new Ajax.Request('' + this.value, {asynchronous:true, evalScripts:true})"

For those wrestling with this kind of thing too, here's what how it works (or at least how this noob made it work):

The long line Ryan just helped me write is in a partial _select_advertformat.rhtml that is rendered from adverts/new.rhtml. It's the only bit of necessary code in that partial.

When a selection is made via the drop-down box, the mediumrectangle.rjs file or the verticalrectangle.rjs is called into action depending on which option is selected. These files sit alongside the rhtml files in the views/adverts folder. The e.g. mediumrectangle.rjs file contains this one line:

page.replace_html("select_advertformat", :partial => "select_mediumrectangle")

This piece of code acts to immediately replace the partial _select_advertformat.rhtml with the partial _select_mediumrectangle.rhtml in adverts/new.rhtml. Whatever is in that latter partial then takes the selection box's place on the page.

I guess it might make more sense to pass the selected value to a single rjs file and have the rjs file work out which partial to render. If that makes sense and someone knows how to do it, it'd be great to hear how it's done.

Many thanks again Ryan.

Re: :onChange issue

ChrisB wrote:

Yay--it worked! Thank you Ryan!

It might be because I have RESTful routes, but I had to delete the foo bit entirely, leaving this:

:onChange => "new Ajax.Request('' + this.value, {asynchronous:true, evalScripts:true})"

That makes sense, I forgot it uses a relative path. You can simplify it to this though (no point in adding an empty string).

:onChange => "new Ajax.Request(this.value, {asynchronous:true, evalScripts:true})"

ChrisB wrote:

I guess it might make more sense to pass the selected value to a single rjs file and have the rjs file work out which partial to render. If that makes sense and someone knows how to do it, it'd be great to hear how it's done.

Yeah, I think that would be better. You wouldn't have to manually write the javascript this way either. Going back to remote_function I believe you can pass a ":with" parameter to do what you want:

:onChange => remote_function(:url => 'advertformat', :with => "'value=' + this.value")

You can then access params[:value] in the resulting action (advertformat or whatever) and it should return the value of the selection.

Railscasts - Free Ruby on Rails Screencasts

Re: :onChange issue

Yes, it works without the empty string (I guess you have to be a real noob not to find that blatantly obvious).

I'll soon have a bash at accessing params[:value] from the resulting action. At the risk of repeating myself in endless rjs files, I'll first get the app set up with one rjs file paired with each partial.

Your help here has been great. I've bought a few Rails/JavaScript/Ajax books lately, and none of them gave me a clear idea of how to do this like you just did. Thank you so much!