jQuery Autocomplete with HTML in Dropdown Selection Menu

With jQuery 1.8 and prior, you could include some simple HTML in the selection menu and it would render. With post 1.8 converting the results as strings, the HTML failed to render.

Workaround

The source page (states.php) for the jQuery is coded as such:

try {
  $conn = new PDO("mysql:host=$dbhost;dbname=$dbname", $dbuser, $dbpass);
}
catch(PDOException $e) {
    echo $e->getMessage();
}

$return_arr = array();

if ($conn)
{
	$ac_term = "%".$_GET['term']."%";
	$query = "SELECT * FROM states where state like :term";
	$result = $conn->prepare($query);
	$result->bindValue(":term",$ac_term);
	$result->execute(); 

	/* Retrieve and store in array the results of the query.*/
	while ($row = $result->fetch(PDO::FETCH_ASSOC)) {
		$row_array['id'] = $row['id'];
		$row_array['value'] = trim($row['state'],"\r");
		$row_array['label'] = "<img src='me.jpg' height='20'>" . trim($row['state'],"\r");
		$row_array['abbrev'] = $row['abbrev'];

        array_push($return_arr,$row_array);
    }

}
/* Free connection resources. */
$conn = null;
/* Toss back results as json encoded array. */
echo json_encode($return_arr);

The example simply concatenates on an image file. For the purpose of demonstration, the image is the same for all results.

Since the latest versions of jQuery are now replacing the ‘<' and '>‘ with (ampersand)lt; and (ampersand)gt; respectively, the results need to be looped and corrected. This can be done in the ‘open’ event of the autocomplete. For more information on the ‘open’ event, see the jQuery UI documentation.

The latest version of jquery causes the item altered in the open event to be too wide. The override of the renderItem function fixes this.

$("#state").autocomplete({
				source: "states_image.php",
				minLength: 2,
				select: function(event, ui) {
					$('#state_id').val(ui.item.id);
					$('#abbrev').val(ui.item.abbrev);
				}
			});
			
			$["ui"]["autocomplete"].prototype["_renderItem"] = function( ul, item) {
				return $( "<li></li>" ) 
  				.data( "item.autocomplete", item )
  				.append( $( "<a></a>" ).html( item.label ) )
  				.appendTo( ul );
			};

So you get something that looks like this:

Demo

Usual recommended jQuery and CF reading:

Posted in ColdFusion, jquery. Tags: , . Permalink. Both comments and trackbacks are closed.

6 Comments

  1. June 6, 2011 at 6:48 pm | Permalink

    So the problem had to do my JSON not being loaded before executing. It's pretty simple mistake, but I discovered it from your comment about the callback. I ran a console.log(item) and it turned up undefined.

    within $(document).ready…

    $.ajax({
    url: 'JSON-list.php',
    dataType: "json",
    success: function(data) {
    $("#category").autocomplete({
    source: data,
    select: function(event, ui) {
    $('#category').val(ui.item.label); //change input values
    $('#categoryHidden').val(ui.item.category); // change hidden input value
    }
    });
    }
    });

  2. June 3, 2011 at 7:15 pm | Permalink

    @Miles
    You need to filter results pulled from a database before the json is built. I can't tell from your code if that is what you are doing.

    See my complete post on using the jquery autocomplete with PHP and mySQL:

    http://www.jensbits.com/2010/03/29/jquery-ui-autocomplete-widget-with-php-and-mysql/

    And, here the explanation for a database query as the source from the jquery ui site (http://jqueryui.com/demos/autocomplete/ ):

    The third variation, the callback, provides the most flexibility, and can be used to connect any data source to Autocomplete. The callback gets two arguments:

    A request object, with a single property called "term", which refers to the value currently in the text input. For example, when the user entered "new yo" in a city field, the Autocomplete term will equal "new yo".

    A response callback, which expects a single argument to contain the data to suggest to the user. This data should be filtered based on the provided term, and can be in any of the formats described above for simple local data (String-Array or Object-Array with label/value/both properties).

  3. June 3, 2011 at 7:03 pm | Permalink

    shoot. url for JSON is incorrect.

  4. June 3, 2011 at 7:01 pm | Permalink

    Pulling from the database.
    here's my jquery ui. this is the local vars version, which works

    header('Cache-Control: no-cache, must-revalidate');
    header('Expires: Mon, 26 Jul 2030 05:00:00 GMT');
    header('Content-type: application/json');

    after the request
    if ($row = mysql_fetch_array($result)) {
    do {
    $json = array();
    //
    //
    $json["label"] = $row['pro_title'];
    $json["value"] = $row['pro_title'];
    $json["category"] = $row['pro_id'];
    $data[] = $json;
    } while($row = mysql_fetch_array($result));
    } else {}

    echo json_encode($data);

  5. June 3, 2011 at 6:34 pm | Permalink

    @Miles
    What is myOutputFile.php doing? Does it just echo the json string or are you pulling from a database?

  6. June 3, 2011 at 6:24 pm | Permalink

    Following your tutorial, have you encountered a JSON problem where the entire list shows with no filtering. I've tried

    var availableCats = [{"value":"Matsumoto Jquery","label":"Matsumoto Jquery","category":"217"},{"value":"Matsumoto Design Mobile","label":"Matsumoto Design Mobile","category":"216"}]

    $("#category").autocomplete({
    source: availableCats
    });

    This works. When i put source: "myOutputFile.php" it shows all the options with no filtering.