Ruby on Rails
HowToUseAdvancedAutocompleteFeatures (Version #65)

Note that there’s easier ways to do this built into newer versions of Rails, this was written in the early days of the framework. If I get a chance, maybe I’ll update.

I’ve been doing some advanced AJAX autocomplete stuff for a client, a pharmacy that wants doctors to fill prescriptions online. This means very efficient entry, because of the high volume of prescriptions to be entered. Here’s a couple things I learned in the process. I’m no Javascript wizard, if anybody sees a cleaner way of doing this code, please make suggestions.

Note that this is probably a fairly advanced topic.

Completing Multiple Form Fields

The “patient name” field uses AJAX for autocomplete. But when a patient is selected from the drop-down list, it also fills in birthdate, address, phone, etc. The Rails helpers can’t handle this kind of thing, so there’s more Javascript involved.

In the view:


<input autocomplete="off" id="patient_name" name="patient[name]" \
size="28" type="text" value="<%= @patient.name %>;" />;
<div class="auto_complete" id="patient_name_auto_complete">;

;
;


In the controller:


  def auto_complete_for_patient_name
    value = params[:patient][:name]
    @patients = Patient.find(:all,
      :conditions =>; ['doctor_id = ? AND LOWER(name) LIKE ?',
                               @user.id, "%#{value.downcase}%"],
      :order =>; 'name ASC',
      :limit =>; 10)
    render :partial =>; 'patients'
  end

In _patients.rhtml:

<ul class="patients">;
  <% for patient in @patients -%>;

  • ;
    ;<= patient.name %>;;

    ;
    ;<= patient.street >;;
    ;<= patient.city %>;
    ;

    ;<= patient.state %>;;
    ;<= patient.zip >;;
    ;<= patient.phone >;;
    ;<= patient.birthdate.month %>;
    ;

    ;<= patient.birthdate.day %>;;
    ;<= patient.birthdate.year %>;
    ;
  • ;
    <% end -%>;

    ;

    The first part of this is basically like what the auto_complete_for_text_field helper does. In updateElement() I clean the whitespace out of the div I got from _patients.rhtml, and then I stick the information into the various text fields using the $() function from Prototype and a little DOM-walking. Note that I skip dn[1] because that’s the <br />; element inbetween the patient’s name and address. The last line sets the focus to the field after all the patient information, since that’s now filled in at this point.

    Inside the controller, it’s pretty straightforward. I find all the patients this doctor has filled for before whose name begins the same as what’s been typed so far, then I render a partial.

    The structure of the partial is tied closely to what is done in the updateElement() Javascript function, which is a bit ugly but works. The patient name and address are displayed to the user inside the autocomplete drop-down, and the rest of the fields are passed to the view but hidden in the drop-down. They are there simply to fill in the form fields when selected.

    To be continued…

    This is a nice tutorial, unfortunately it doesn’t work. In your earlier revision of the page you said: “This won’t work without a small modification to the script.aculo.us source code, which I’ve submitted to be included in the next version.” Is the modification you mention included in the 1.5_pre3 version (which I’m currently using)? I’m also using the latest version of rails (0.13.1) and prototype.js (1.4.0_pre2 from CVS).

    Has anyone manged to get this to work? I’m quite interested in getting something like this to work and this is the only tutorial I have found.

    —Alex

    I just got something (kind of) similar working using the latest prototype.js and script.aculo.us files. In my case I wanted behavior like an html select element: display text but store the ID of an object. When the user selects a choice, the corresponding ID is stored in a hidden form field. Using the techniques in the above example and information from this patch it wasn’t too hard. I think the same hook described in the patch could make the above example work.

    —Krishna

    Alex—the small change I was talking about only allows the line $(‘rx_drug’).focus() to work correctly, so the focus immediately moves to the next form field. 1.5_pre3 includes this change. The rest of this will work fine without it, though, so it’s probably something else that’s stopping you. I would suggest getting this working with the AJAX helpers first, to make sure you’ve got that right, and then iterate towards the final code from there.

    Krishna—afterUpdateElement() isn’t quite what I needed, as didn’t want to use the original updateElement() method body at all, but it’ll definitely come in handy in other situations, like you’ve described.

    Brian—thanx for the nice tutorial – as Alex stated it didn’t work for a few reasons – that I’ve been able to work through over multiple cups of coffee. I’ve highlighted my changes above in bold[damn textile renders don’t appear to be working. sigh. you’ll have to look for **’s to see my comments]. Just new to rails, this method for populating field values is mucho better than a multiple trip method I was working on previously. Thank you.

    —Jodi

    Thanks for the fixes, Jodi. Yes, you need the div, and yes the comment I had in there screws up the DOM parsing. I should have known better than to make code changes while copy-and-pasting to a wiki article. :) Sorry about the confusion.

    Brian Palmer (original creator of the page, before i2 move)

    Can anyone explain how @user.id is passed in? I’m trying to do something similar: select patient group from dropdown, then autocomplete on patient names that have that group id.

    —Kevin

    That’s not really important to the tutorial. It’s just a variable I happened to define and use to access the database.

    Brian Palmer

    What is this “autocomplete” attribute in the HTML? I can’t see mention of this anywhere in the HTML or XHTML specifications, so does this make this example invalid markup? Is there a way to do this using CSS or JavaScript instead? (If it’s possible by JavaScript, we should quickly nag someone to put it into the autocomplete helper so that we don’t have to think about it!)

    —AnonymousCoward

    The “autocomplete” is non-standard, in the same way that AJAX is non-standard (in other words, not in the spec but all major browsers support it). If you use the rails helper methods, it adds this as well, and I wouldn’t recommend skipping it or your UI will be severely broken.

    Brian Palmer

    The autocompleter is working for me in firefox. Its not working in IE7 (beta3)?

    Note that there’s easier ways to do this built into newer versions of Rails, this was written in the early days of the framework. If I get a chance, maybe I’ll update.

    I’ve been doing some advanced AJAX autocomplete stuff for a client, a pharmacy that wants doctors to fill prescriptions online. This means very efficient entry, because of the high volume of prescriptions to be entered. Here’s a couple things I learned in the process. I’m no Javascript wizard, if anybody sees a cleaner way of doing this code, please make suggestions.

    Note that this is probably a fairly advanced topic.

    Completing Multiple Form Fields

    The “patient name” field uses AJAX for autocomplete. But when a patient is selected from the drop-down list, it also fills in birthdate, address, phone, etc. The Rails helpers can’t handle this kind of thing, so there’s more Javascript involved.

    In the view:

    
    <input autocomplete="off" id="patient_name" name="patient[name]" \
    size="28" type="text" value="<%= @patient.name %>;" />;
    <div class="auto_complete" id="patient_name_auto_complete">;

    ;
    ;


    In the controller:

    
      def auto_complete_for_patient_name
        value = params[:patient][:name]
        @patients = Patient.find(:all,
          :conditions =>; ['doctor_id = ? AND LOWER(name) LIKE ?',
                                   @user.id, "%#{value.downcase}%"],
          :order =>; 'name ASC',
          :limit =>; 10)
        render :partial =>; 'patients'
      end
    

    In _patients.rhtml:
    
    <ul class="patients">;
      <% for patient in @patients -%>;

  • ;
    ;<= patient.name %>;;

    ;
    ;<= patient.street >;;
    ;<= patient.city %>;
    ;

    ;<= patient.state %>;;
    ;<= patient.zip >;;
    ;<= patient.phone >;;
    ;<= patient.birthdate.month %>;
    ;

    ;<= patient.birthdate.day %>;;
    ;<= patient.birthdate.year %>;
    ;
  • ;
    <% end -%>;

    ;

    The first part of this is basically like what the auto_complete_for_text_field helper does. In updateElement() I clean the whitespace out of the div I got from _patients.rhtml, and then I stick the information into the various text fields using the $() function from Prototype and a little DOM-walking. Note that I skip dn[1] because that’s the <br />; element inbetween the patient’s name and address. The last line sets the focus to the field after all the patient information, since that’s now filled in at this point.

    Inside the controller, it’s pretty straightforward. I find all the patients this doctor has filled for before whose name begins the same as what’s been typed so far, then I render a partial.

    The structure of the partial is tied closely to what is done in the updateElement() Javascript function, which is a bit ugly but works. The patient name and address are displayed to the user inside the autocomplete drop-down, and the rest of the fields are passed to the view but hidden in the drop-down. They are there simply to fill in the form fields when selected.

    To be continued…

    This is a nice tutorial, unfortunately it doesn’t work. In your earlier revision of the page you said: “This won’t work without a small modification to the script.aculo.us source code, which I’ve submitted to be included in the next version.” Is the modification you mention included in the 1.5_pre3 version (which I’m currently using)? I’m also using the latest version of rails (0.13.1) and prototype.js (1.4.0_pre2 from CVS).

    Has anyone manged to get this to work? I’m quite interested in getting something like this to work and this is the only tutorial I have found.

    —Alex

    I just got something (kind of) similar working using the latest prototype.js and script.aculo.us files. In my case I wanted behavior like an html select element: display text but store the ID of an object. When the user selects a choice, the corresponding ID is stored in a hidden form field. Using the techniques in the above example and information from this patch it wasn’t too hard. I think the same hook described in the patch could make the above example work.

    —Krishna

    Alex—the small change I was talking about only allows the line $(‘rx_drug’).focus() to work correctly, so the focus immediately moves to the next form field. 1.5_pre3 includes this change. The rest of this will work fine without it, though, so it’s probably something else that’s stopping you. I would suggest getting this working with the AJAX helpers first, to make sure you’ve got that right, and then iterate towards the final code from there.

    Krishna—afterUpdateElement() isn’t quite what I needed, as didn’t want to use the original updateElement() method body at all, but it’ll definitely come in handy in other situations, like you’ve described.

    Brian—thanx for the nice tutorial – as Alex stated it didn’t work for a few reasons – that I’ve been able to work through over multiple cups of coffee. I’ve highlighted my changes above in bold[damn textile renders don’t appear to be working. sigh. you’ll have to look for **’s to see my comments]. Just new to rails, this method for populating field values is mucho better than a multiple trip method I was working on previously. Thank you.

    —Jodi

    Thanks for the fixes, Jodi. Yes, you need the div, and yes the comment I had in there screws up the DOM parsing. I should have known better than to make code changes while copy-and-pasting to a wiki article. :) Sorry about the confusion.

    Brian Palmer (original creator of the page, before i2 move)

    Can anyone explain how @user.id is passed in? I’m trying to do something similar: select patient group from dropdown, then autocomplete on patient names that have that group id.

    —Kevin

    That’s not really important to the tutorial. It’s just a variable I happened to define and use to access the database.

    Brian Palmer

    What is this “autocomplete” attribute in the HTML? I can’t see mention of this anywhere in the HTML or XHTML specifications, so does this make this example invalid markup? Is there a way to do this using CSS or JavaScript instead? (If it’s possible by JavaScript, we should quickly nag someone to put it into the autocomplete helper so that we don’t have to think about it!)

    —AnonymousCoward

    The “autocomplete” is non-standard, in the same way that AJAX is non-standard (in other words, not in the spec but all major browsers support it). If you use the rails helper methods, it adds this as well, and I wouldn’t recommend skipping it or your UI will be severely broken.

    Brian Palmer

    The autocompleter is working for me in firefox. Its not working in IE7 (beta3)?

    Note that there’s easier ways to do this built into newer versions of Rails, this was written in the early days of the framework. If I get a chance, maybe I’ll update.

    I’ve been doing some advanced AJAX autocomplete stuff for a client, a pharmacy that wants doctors to fill prescriptions online. This means very efficient entry, because of the high volume of prescriptions to be entered. Here’s a couple things I learned in the process. I’m no Javascript wizard, if anybody sees a cleaner way of doing this code, please make suggestions.

    Note that this is probably a fairly advanced topic.

    Completing Multiple Form Fields

    The “patient name” field uses AJAX for autocomplete. But when a patient is selected from the drop-down list, it also fills in birthdate, address, phone, etc. The Rails helpers can’t handle this kind of thing, so there’s more Javascript involved.

    In the view:

    
    <input autocomplete="off" id="patient_name" name="patient[name]" \
    size="28" type="text" value="<%= @patient.name %>;" />;
    <div class="auto_complete" id="patient_name_auto_complete">;

    ;
    ;


    In the controller:

    
      def auto_complete_for_patient_name
        value = params[:patient][:name]
        @patients = Patient.find(:all,
          :conditions =>; ['doctor_id = ? AND LOWER(name) LIKE ?',
                                   @user.id, "%#{value.downcase}%"],
          :order =>; 'name ASC',
          :limit =>; 10)
        render :partial =>; 'patients'
      end
    

    In _patients.rhtml:
    
    <ul class="patients">;
      <% for patient in @patients -%>;

  • ;
    ;<= patient.name %>;;

    ;
    ;<= patient.street >;;
    ;<= patient.city %>;
    ;

    ;<= patient.state %>;;
    ;<= patient.zip >;;
    ;<= patient.phone >;;
    ;<= patient.birthdate.month %>;
    ;

    ;<= patient.birthdate.day %>;;
    ;<= patient.birthdate.year %>;
    ;
  • ;
    <% end -%>;

    ;

    The first part of this is basically like what the auto_complete_for_text_field helper does. In updateElement() I clean the whitespace out of the div I got from _patients.rhtml, and then I stick the information into the various text fields using the $() function from Prototype and a little DOM-walking. Note that I skip dn[1] because that’s the <br />; element inbetween the patient’s name and address. The last line sets the focus to the field after all the patient information, since that’s now filled in at this point.

    Inside the controller, it’s pretty straightforward. I find all the patients this doctor has filled for before whose name begins the same as what’s been typed so far, then I render a partial.

    The structure of the partial is tied closely to what is done in the updateElement() Javascript function, which is a bit ugly but works. The patient name and address are displayed to the user inside the autocomplete drop-down, and the rest of the fields are passed to the view but hidden in the drop-down. They are there simply to fill in the form fields when selected.

    To be continued…

    This is a nice tutorial, unfortunately it doesn’t work. In your earlier revision of the page you said: “This won’t work without a small modification to the script.aculo.us source code, which I’ve submitted to be included in the next version.” Is the modification you mention included in the 1.5_pre3 version (which I’m currently using)? I’m also using the latest version of rails (0.13.1) and prototype.js (1.4.0_pre2 from CVS).

    Has anyone manged to get this to work? I’m quite interested in getting something like this to work and this is the only tutorial I have found.

    —Alex

    I just got something (kind of) similar working using the latest prototype.js and script.aculo.us files. In my case I wanted behavior like an html select element: display text but store the ID of an object. When the user selects a choice, the corresponding ID is stored in a hidden form field. Using the techniques in the above example and information from this patch it wasn’t too hard. I think the same hook described in the patch could make the above example work.

    —Krishna

    Alex—the small change I was talking about only allows the line $(‘rx_drug’).focus() to work correctly, so the focus immediately moves to the next form field. 1.5_pre3 includes this change. The rest of this will work fine without it, though, so it’s probably something else that’s stopping you. I would suggest getting this working with the AJAX helpers first, to make sure you’ve got that right, and then iterate towards the final code from there.

    Krishna—afterUpdateElement() isn’t quite what I needed, as didn’t want to use the original updateElement() method body at all, but it’ll definitely come in handy in other situations, like you’ve described.

    Brian—thanx for the nice tutorial – as Alex stated it didn’t work for a few reasons – that I’ve been able to work through over multiple cups of coffee. I’ve highlighted my changes above in bold[damn textile renders don’t appear to be working. sigh. you’ll have to look for **’s to see my comments]. Just new to rails, this method for populating field values is mucho better than a multiple trip method I was working on previously. Thank you.

    —Jodi

    Thanks for the fixes, Jodi. Yes, you need the div, and yes the comment I had in there screws up the DOM parsing. I should have known better than to make code changes while copy-and-pasting to a wiki article. :) Sorry about the confusion.

    Brian Palmer (original creator of the page, before i2 move)

    Can anyone explain how @user.id is passed in? I’m trying to do something similar: select patient group from dropdown, then autocomplete on patient names that have that group id.

    —Kevin

    That’s not really important to the tutorial. It’s just a variable I happened to define and use to access the database.

    Brian Palmer

    What is this “autocomplete” attribute in the HTML? I can’t see mention of this anywhere in the HTML or XHTML specifications, so does this make this example invalid markup? Is there a way to do this using CSS or JavaScript instead? (If it’s possible by JavaScript, we should quickly nag someone to put it into the autocomplete helper so that we don’t have to think about it!)

    —AnonymousCoward

    The “autocomplete” is non-standard, in the same way that AJAX is non-standard (in other words, not in the spec but all major browsers support it). If you use the rails helper methods, it adds this as well, and I wouldn’t recommend skipping it or your UI will be severely broken.

    Brian Palmer

    The autocompleter is working for me in firefox. Its not working in IE7 (beta3)?

    Note that there’s easier ways to do this built into newer versions of Rails, this was written in the early days of the framework. If I get a chance, maybe I’ll update.

    I’ve been doing some advanced AJAX autocomplete stuff for a client, a pharmacy that wants doctors to fill prescriptions online. This means very efficient entry, because of the high volume of prescriptions to be entered. Here’s a couple things I learned in the process. I’m no Javascript wizard, if anybody sees a cleaner way of doing this code, please make suggestions.

    Note that this is probably a fairly advanced topic.

    Completing Multiple Form Fields

    The “patient name” field uses AJAX for autocomplete. But when a patient is selected from the drop-down list, it also fills in birthdate, address, phone, etc. The Rails helpers can’t handle this kind of thing, so there’s more Javascript involved.

    In the view:

    
    <input autocomplete="off" id="patient_name" name="patient[name]" \
    size="28" type="text" value="<%= @patient.name %>;" />;
    <div class="auto_complete" id="patient_name_auto_complete">;

    ;
    ;


    In the controller:

    
      def auto_complete_for_patient_name
        value = params[:patient][:name]
        @patients = Patient.find(:all,
          :conditions =>; ['doctor_id = ? AND LOWER(name) LIKE ?',
                                   @user.id, "%#{value.downcase}%"],
          :order =>; 'name ASC',
          :limit =>; 10)
        render :partial =>; 'patients'
      end
    

    In _patients.rhtml:
    
    <ul class="patients">;
      <% for patient in @patients -%>;

  • ;
    ;<= patient.name %>;;

    ;
    ;<= patient.street >;;
    ;<= patient.city %>;
    ;

    ;<= patient.state %>;;
    ;<= patient.zip >;;
    ;<= patient.phone >;;
    ;<= patient.birthdate.month %>;
    ;

    ;<= patient.birthdate.day %>;;
    ;<= patient.birthdate.year %>;
    ;
  • ;
    <% end -%>;

    ;

    The first part of this is basically like what the auto_complete_for_text_field helper does. In updateElement() I clean the whitespace out of the div I got from _patients.rhtml, and then I stick the information into the various text fields using the $() function from Prototype and a little DOM-walking. Note that I skip dn[1] because that’s the <br />; element inbetween the patient’s name and address. The last line sets the focus to the field after all the patient information, since that’s now filled in at this point.

    Inside the controller, it’s pretty straightforward. I find all the patients this doctor has filled for before whose name begins the same as what’s been typed so far, then I render a partial.

    The structure of the partial is tied closely to what is done in the updateElement() Javascript function, which is a bit ugly but works. The patient name and address are displayed to the user inside the autocomplete drop-down, and the rest of the fields are passed to the view but hidden in the drop-down. They are there simply to fill in the form fields when selected.

    To be continued…

    This is a nice tutorial, unfortunately it doesn’t work. In your earlier revision of the page you said: “This won’t work without a small modification to the script.aculo.us source code, which I’ve submitted to be included in the next version.” Is the modification you mention included in the 1.5_pre3 version (which I’m currently using)? I’m also using the latest version of rails (0.13.1) and prototype.js (1.4.0_pre2 from CVS).

    Has anyone manged to get this to work? I’m quite interested in getting something like this to work and this is the only tutorial I have found.

    —Alex

    I just got something (kind of) similar working using the latest prototype.js and script.aculo.us files. In my case I wanted behavior like an html select element: display text but store the ID of an object. When the user selects a choice, the corresponding ID is stored in a hidden form field. Using the techniques in the above example and information from this patch it wasn’t too hard. I think the same hook described in the patch could make the above example work.

    —Krishna

    Alex—the small change I was talking about only allows the line $(‘rx_drug’).focus() to work correctly, so the focus immediately moves to the next form field. 1.5_pre3 includes this change. The rest of this will work fine without it, though, so it’s probably something else that’s stopping you. I would suggest getting this working with the AJAX helpers first, to make sure you’ve got that right, and then iterate towards the final code from there.

    Krishna—afterUpdateElement() isn’t quite what I needed, as didn’t want to use the original updateElement() method body at all, but it’ll definitely come in handy in other situations, like you’ve described.

    Brian—thanx for the nice tutorial – as Alex stated it didn’t work for a few reasons – that I’ve been able to work through over multiple cups of coffee. I’ve highlighted my changes above in bold[damn textile renders don’t appear to be working. sigh. you’ll have to look for **’s to see my comments]. Just new to rails, this method for populating field values is mucho better than a multiple trip method I was working on previously. Thank you.

    —Jodi

    Thanks for the fixes, Jodi. Yes, you need the div, and yes the comment I had in there screws up the DOM parsing. I should have known better than to make code changes while copy-and-pasting to a wiki article. :) Sorry about the confusion.

    Brian Palmer (original creator of the page, before i2 move)

    Can anyone explain how @user.id is passed in? I’m trying to do something similar: select patient group from dropdown, then autocomplete on patient names that have that group id.

    —Kevin

    That’s not really important to the tutorial. It’s just a variable I happened to define and use to access the database.

    Brian Palmer

    What is this “autocomplete” attribute in the HTML? I can’t see mention of this anywhere in the HTML or XHTML specifications, so does this make this example invalid markup? Is there a way to do this using CSS or JavaScript instead? (If it’s possible by JavaScript, we should quickly nag someone to put it into the autocomplete helper so that we don’t have to think about it!)

    —AnonymousCoward

    The “autocomplete” is non-standard, in the same way that AJAX is non-standard (in other words, not in the spec but all major browsers support it). If you use the rails helper methods, it adds this as well, and I wouldn’t recommend skipping it or your UI will be severely broken.

    Brian Palmer

    The autocompleter is working for me in firefox. Its not working in IE7 (beta3)?

    Created on December 14, 2006 12:27 by Art (217.173.179.79)