views:

33

answers:

2

Hey, this is the first time I've actually finished writing up a question without SO giving me the answer in the process. :)

I've got a nested form (along the lines of Ryan Bates' Railscast tutorial on the topic) which allows users to dynamically add additional fields for adding/removing nested models using Prototype-based javascript. The extra fields can be added and removed and work just fine to create new models.

The problem is, one of the fields uses an Ajax.Autocompleter; the code in the page when the partial is rendered looks like this:

<script type="text/javascript">
//<![CDATA[
new Ajax.Autocompleter(...various args...);
//]]>
</script>

The autocompleter works fine if the partial is rendered to begin with (eg, if the form starts out with one instance of the partial, or when editing existing nested models). However, it doesn't work in the dynamically added form fields.

I have tried using both insert() and just setting the innerHTML of an empty div to insert the HTML partial. With insert(), the Autocompleter code is evaluated and everything in the <script> tag vanishes (as I understand is expected), but the autocomplete does not work. With setting the innerHTML, the script appears exactly as it does in the pre-rendered partial, but the autocompleter still doesn't get invoked.

I suspect that this has something to do with how the evalScripts works, and I've found some documentation on the subject, but I'm having a hard time working out how to apply it to the Autocompleter declaration.

Any advice hugely appreciated!

ETA: adding the javascript used to add in the new section:

  function add_section(link, nested_model_name, content) {
      // get the right new_id which should be in a div with class "last_id" at the bottom of 
      // the nearest section
      var last_id = parseInt($(link).up().previous('.last_id').innerHTML);
      var new_id = last_id + 1;
      var regexp = new RegExp("new_" + nested_model_name, "g");
      content = content.replace(regexp, new_id)

      // this is the line that actually inserts the content into the page
      $(link).up().insert({before: content});
  }

Debugging with firebug shows that the content is correct (ie has the normally-working autocomplete code in it) before it is inserted.

A: 

is your JS to register the autocompleter within your script-tag you're loading via ajax.updater? if so, you have to add the evalScript parameter to have it eval'ed: new Ajax.Updater('target',url,{method:'get', evalScripts:true});

koko
Thanks for the try but unfortunately no -- I've added the javascript function that adds the new section to my original question for more clarity. I just mean that with `insert()` Prototype is trying to evaluate the script, presumably in the same way it does using Ajax.Updater with evalScripts set to true.
shalott
A: 

Okay, so as an experiment I tried just changing my Autocompleter helper code as follows and now it works fine:

FROM:

javascript_tag("new Ajax.Autocompleter(...

TO:

javascript_tag("var autocomplete_for_#{fieldname} = new Ajax.Autocompleter(...

This is in in a Rails helper, but unless I misunderstand, I think the point is that by declaring a variable, it's causing prototype to actually evaluate the new call as it inserts the code.

(Any more/better insight into why this works and the other doesn't would still be v welcome though, since right now this was mostly blind luck.)

shalott