AJAX Auto Complete

I recently came across the problem of using multiple input_auto_complete_tag’s. The problem was I needed to store the ID of my first category somewhere, so I could filter the sub-categories returned in the second input_auto_complete_tag. Also, just to make things a little more complicated, there is a third input_auto_complete_tag that needs results filtered by the previous IDs.

Follow me, as I take you through a quick tutorial of how I did it:

Form Template:

Firstly we need create our form with the three auto completing inputs. To enable us to store the IDs that are returned we’ll put in a hidden tag for each input tag. Also to enable us to get the ID of the selected result, we’ll need a tiny bit of Javascript which runs after selecting the result.

/apps/app/modules/module/templates/formSuccess.php

<?php use_helper('Javascript'); ?>
<p><?php
  // SELECT A
  echo
    input_hidden_tag('select_a_id', '').
    input_auto_complete_tag(
      'select_a',
      '',
      'module/autoComplete?select=a',
      array('autocomplete' => 'off'),
      array(
        'use_style'             => true,
        'after_update_element'  => "function (inputField, selectedItem) { $('select_a_id').value = selectedItem.id; }"
      )
    );
?></p>
<p><?php
  // SELECT B
  echo
    input_hidden_tag('select_b_id', '').
    input_auto_complete_tag(
      'select_b',
      '',
      'module/autoComplete?select=b',
      array('autocomplete' => 'off'),
      array(
        'use_style'             => true,
        'after_update_element'  => "function (inputField, selectedItem) { $('select_b_id').value = selectedItem.id; }",
        'with'                  => " value+'&amp;select_a_id='+$('select_a_id').value"
      )
    );
?></p>
<p><?php
  // SELECT C
  echo
    input_hidden_tag('select_c_id', '').
    input_auto_complete_tag(
      'select_c',
      '',
      'module/autoComplete?select=c',
      array('autocomplete' => 'off'),
      array(
        'use_style'             => true,
        'after_update_element'  => "function (inputField, selectedItem) { $('select_c_id').value = selectedItem.id; }",
        'with'                  => " value+'&amp;select_a_id='+$('select_a_id').value+'&amp;select_b_id='+$('select_b_id').value"
      )
    );
?></p>

The ‘after_update_element’ simply takes the ID from the element we’ve clicked on, in the results of the auto complete function and places it into the hidden tag.

Select B and Select C use the ‘with’ argument to send the ID of the previous selects to our auto complete function (module/autoComplete) enabling us to filter the results we’ll display in the input_auto_complete_tag.

Auto Complete Function:

The auto complete function will be called everytime we’re typing into one of the input_auto_complete_tag’s. As you can see in the code above, we’re also passing through a parameter (eg. module/autoComplete?select=a) specifying which input is calling the function.

/apps/app/modules/module/actions/actions.class.php

<?php
  public function executeAutoComplete()
  {
    // Get which input called the function
    $input = $this->getRequestParameter('select');
    // Get what the user has typed
    $typed = $this->getRequestParameter('select_'.$input);
 
    // Depending what input called this generate $db_results for the template
    switch ( $input )
    {
      case 'a':
 
        //... generate $db_results
 
        break;
 
      case 'b':
        // Get the IDs of previous inputs
        $a_id = $this->getRequestParameter('select_a_id');
 
        //... generate $db_results using $a_id to filter results
 
        break;
 
      case 'c':
        // Get the IDs of previous inputs
        $a_id = $this->getRequestParameter('select_a_id');
        $b_id = $this->getRequestParameter('select_b_id');
 
        //... generate $db_results using $a_id and $b_id to filter results
 
        break;
    }
 
    // Create array with the ID and Name
    $results = array();
    foreach ( $db_results as $row )
    {
      $results[ $row->getId() ] = $row->getName();
    }
 
    // Pass results to the template
    $this->results = $results;
  }
?>

I’ll leave you to generate the database results, as this is very specific to your database model. Although as a hint, it’s usually best to use an LIKE query:

$criteria->add( YourTablePeer::NAME, $typed.'%', Criteria::LIKE );

Auto Complete Template:

/apps/app/modules/module/templates/autoCompleteSuccess.php

  <ul>
    <?php foreach ( $results as $key => $value ): ?>
      <li id="<?php echo $key ?>"><?php echo $value ?></li>
    <?php endforeach; ?>
  </ul>

The auto complete template simply returns a unordered list which will be displayed on our form for the user to select from.

It’s really as easy as that, but if you’ve got any questions or queries about how to get it working for you, please leave a comment and I’ll try and help you out.

Written by Rob | Posted on April 4th, 2008 in symfony |

14 Comments to “AJAX Auto Complete”

  1. Josh says:

    Thanks alot for this, I’m sure it’ll come in use for my project i’m currently working on :D.

  2. Andrzej says:

    hi
    I have I problem with auto complete. I have to pass to autocomplete action value of a radiobutton. My problem is whenever I pass a value of radiobutton I’m loosing value of input box and vice versa. I use something like this:
    ‘off’),
    array(’use_style’ => true, ‘with’ => “‘&radio=’ + $(’radio’).checked”)
    )?>
    Do you have an idea what seems to be a problem?

  3. Andrzej says:

    sorry, don’t know how to past the code in here…

  4. Rob (the author) says:

    Hi Andrzej,

    I think you need to make a slight change to your options array like the following:

    array(’use_style’ => true, ‘with’ => ” value+’&radio=’+$(’radio’).checked”)

    Take note of the value+ before your radio value bit. Please let me know how you get on with this.

    Thanks,

    Rob
    Symfony-Blog.co.uk

  5. Peter says:

    Guys,
    I’m using Firefox 2.0.0.14 and I am new to Symfony. (using 1.0).
    I setup your example and I get the autocomple to work fine in the sense that
    the data is pulled from the database into an tag. When I click the “down” arrow to navigate my list, everything works fine… each item is highlighted, but when I click the “up” arrow to go back up the list, everything goes screwy. The listed items start to appear and disappear everytime I click the “up” arrow on my keyboard. I’m thinking this has something to do with main.css and/or view.yml. Can you tell me if you have any special css to get this to work, and/or what view.yml needs to be set for the action that does the autocomplete.

    I’ll paste my code pieces here…

    my template: createSuccess.php

    Name:

     'off'),
          array(
            'use_style'             => true,
            'after_update_element'  => "function (inputField, selectedItem) { $('select_a_id').value = selectedItem.id; }"
          )
        );
    ?>

    my products autocomplete action in actions.class.php

      public function executeAutoComplete()
      {
        // Get which input called the function
        $input = $this->getRequestParameter('select');
        // Get what the user has typed
        $typed = $this->getRequestParameter('select_'.$input);
     
        $this->productss = ProductsPeer::retrieveByLike($typed);
        $partial = get_partial('products',array('products' => $this->productss ));
        return $this->renderText($partial);
     
      }

    — my partial _products.php

    <li id="<?php echo getId() ?>"><?php echo getName() ?>

    Like I said, I get the data fine from the database, but the display and the navigation of the list is screwy. I also need the extra “” in my template because without them, I don’t see the full list of items returned by my query…so it has something to do with the layout.
    I can provide screen prints if it makes it easier to follow.
    Any help would be greatly appreciated.

    -p

  6. Peter says:

    BTW, the _products.php didn’t past in correctly. It looks just like your example except that I use the getIdIO and getName() functions to build my LI tag.
    -p

  7. Rajesh says:

    I’m using the same code but i’cant call the input_auto_complete_tag…
    please reply why i can’t call.

    thanks

  8. Rob (the author) says:

    Rajesh… Are you definitely including the helper? For example:

    <?php use_helper('Javascript'); ?>
  9. Rob (the author) says:

    Peter… It looks like your partial _products.php is only printing stuff like this

    <li id="1">Name

    Which would mean your list is bad HTML, which might cause the problem. You need your list to be well formed like so:

    <ul>
      <li id="1">Name 1</li>
      <li id="2">Name 2</li>
      <li id="3">Name 3</li>
      <li id="4">Name 4</li>
    </ul>

    Please let me know if this was the problem?

  10. Peter says:

    Rob,
    thanks for getting backed to me, its going on 2 weeks now and I can’t seem to
    figure this one out. I think when I past my code fragments in here, sometimes they get messed up. This time I tried it and while I had my 4 choices in the list, I checked Firebug to see what the actual code looked like. Based on that it looks like my tags are okay.

    This is what firebug shows me when I inspect the html.

    Product_ID:

    Name: Enter a product name:

    Blue Red Bear
    Blond Pink Doll
    Batman Bear
    Ball Bear

    //

    If you would like, I would be happy to send you my code .. its pretty small and easy to read.

    -p

  11. Peter says:

    Rob,
    my code fragment didn’t past in correctly above. All the html was translated instead of it actually showing all the tags.
    I was able to past in my code into the symfony forums, but nobody seems to want to touch this one.
    Here is the URL.
    http://www.symfony-project.org/forum/index.php/t/15466/

    Any help would be tremendously appreciated.
    thanks.
    -p

  12. Vadim says:

    Thanks Rob, it was the most useful example I could find.

  13. Vadim says:

    By the way, Rob - what about an autocompletion in symfony 1.1? The same using of input_auto_complete_tag? Is this symfony’s new form model style - what do you think?

  14. jpromerobx says:

    Thanks Rob for this usefull example. It solve some problems with the input_auto_complete_tag for my project.

Leave a Reply