2

I'm trying to set up an autocomplete that's getting its data from a csv. The csv has a list of restaurant names and food types. I've gone over some of the other posts here at SO, and the autocomplete documentation, but I think it's the two fields in the csv, rather than one field that is tripping me up.

Example csv data:

McDonald's,Fast Food
Olive Garden,Italian
Manny's,Steakhouse
Carino's,Italian
etc...

The user should be able to search by either food type or restaurant name:

<body>
    <br>
    <br>
    <label id="lblSearchRestaurant" for="txtSearchRestaurant">Search for a Restaurant</label>
    <input type="text" id="txtSearchRestaurant">
</body>

Here's what I've tried for the autocomplete setup:

$(function() {
    $( "#txtSearchRestaurant" ).autocomplete({
        source:searchRestaurant.php,
        select: function( event, ui ) {
            $( "#search" ).val( ui.item.label + " / " + ui.item.actor );
            return false;
        }
    }).data( "ui-autocomplete" )._renderItem = function( ul, item ) {
        return $( "<li>" )
        .data( "item.autocomplete", item )
        .append( "<a><strong>" + item.label + "</strong> / " + item.actor + "</a>" )
        .appendTo( ul );
    };
});

I need to serve the data using a PHP script. Here's what I have at this point:

<?php
$header = NULL;
$restaurants = array();

if (($file = fopen('restaurants.csv', 'r')) !== FALSE) {
    while (($row = fgetcsv($file, 1000, ',')) !== FALSE) {
        if(!$header)
            $header = $row;
        else
            $data[] = array_combine($header, $row);
    }
    fclose($file);
}

$term = $_GET['term']; 

foreach($restaurants as $k=>$v) { 
    if(preg_match("/^$term/i", $v)) { $return[] = $v; } 
}
foreach($restaurants as $k => $v) { 
    if(preg_match("/$term/i", $v)) { $return[] = $v; } 
} 
echo json_encode(array_values(array_unique($return)));

None of the above has worked, so I tried formating the restaurant data in to an array, rather than just comma-separated values:

[
{name:"McDonald's",type:"Fast Food"},
{name:"Olive Garden",type:"Italian"},
{name:"Manny's",type:"Steakhouse"},
{name:"Carino's",type:"Italian"}
];

I tried that locally in the <script> tag and in a separate file, but neither worked.

So, none of the above worked for me, but I'm not the best at arrays yet and for that matter, using JSON data, so I probably don't have the php script set up properly.

I'd appreciate it if someone could point me in the right direction here.

Thanks.

Note to potential answers: The jquery UI autocomplete, the format of the incoming data (as described above) and using PHP to get the data from the csv to the autocomplete are all requirements for this. Those three stipulations are, unfortunately, not under my control.

marky
  • 4,878
  • 17
  • 59
  • 103
  • Plenty of views but no replies - did I stump the masses? C'mon, guys! Lend me a hand here! – marky May 22 '13 at 10:04

4 Answers4

1

Here's a jsfiddle that I hope does what you want: http://jsfiddle.net/L8L6k/

The javascript has a variable "data" at the top that you will need to populate with your data, using PHP (I believe you said you could do this.)

This data is then combined into two variables:

var autocomp = new Array();
var hash = new Array();
for (var i=0; i < data.length; i++)
{
    autocomp[i] = data[i].name + ' ' + data[i].type;
    hash[autocomp[i]] = data[i];
}

1) A simple array, autocomp, that is just a concatenation of the two values, name and type. This is passed to the JQuery UI autocomplete as the source. This way autocomplete will search both your "item" and "type".

2) An associative array, hash, which associates the data object with the concatenated value.

Both the select function and the renderItem function use this hash to get the original data object:

$( "#txtSearchRestaurant" ).autocomplete({
    source:autocomp,
    select: function( event, ui ) {
        var d = hash[ui.item.label];
        $( "#txtSearchRestaurant" ).val( d.name + " / " + d.type );
        return false;
    }
}).data( "ui-autocomplete" )._renderItem = function( ul, item ) {
    var d = hash[item.label];
     return $( "<li>" )
    .data( "item.autocomplete", d )
    .append( "<a><strong>" + d.name + "</strong> / " + d.type + "</a>" )
    .appendTo( ul );
};
Bumptious Q Bangwhistle
  • 4,689
  • 2
  • 34
  • 43
0

I'm not that familiar with PHP, but this generally seems like you are unclear on the concepts. Note to readers: lack of response often indicates an unclear formulation of the question.

Correct me if I'm wrong, but here is how I understand the problem from your description:

  1. You have a CSV of <restaurant>,<cuisine> pairs.
  2. You have an omnibox on a web page where a user can enter restaurant or cuisine.
  3. You want the omnibox to autocomplete based on the CSV.
  4. You want to use the jQuery autocomplete widget to help with this.

The code you have presented tells a different story. The PHP code seems to be doing pretty much nothing. It stuffs a lot of data from a file into a data[] and then does nothing with it. I have no idea what that function produces.

Setting that aside, the HTML you present is a <body> block that contains an input type and a label for that type. (That's okay for this kind of discussion.)

The JavaScript/jQuery, however, is barely related. I don't see why UI items are expected to have a label and an actor. The general display of the auto-complete suggests you want to keep the restaurant and cuisine together and show them as a single selector but you want to have them select on either. This is not something the widget provides "straight out of the box" but it has hooks where you can add code to accomplish what you want.

A good place to start is to realize that while the widget is helpful, it is not meant to deal with multivalued objects. You're going to have to do some significant customization.

Old Pro
  • 24,624
  • 7
  • 58
  • 106
  • I understand your points, but as it is, I have been given this situation to solve. I am required to make a functional jQuery UI autocomplete populated from a csv file with a specific format using PHP to server the data to the JS. By the way, if my question is unclear and no one is answering because of that, then at the very least the readers who required more info to answer perhaps should have let me know that. Maybe I could have had this solved a lot sooner if they had. ;) – marky Jun 03 '13 at 10:31
  • It doesn't seem to me you understand my points. We are all volunteers here with way more questions to answer than we have time for; it is up to the asker to make their question clear enough and interesting enough for someone to want to answer it. Your description is vague, your code doesn't match your description, and it is obvious that you need a lot more education and training that we can provide here. SO is about providing education by answering well-defined questions of general interest. This question reads more like 'please write code for me because I am in over my head'. – Old Pro Jun 03 '13 at 14:38
  • For an example of a well-asked question, see http://stackoverflow.com/q/16435428/712765 – Old Pro Jun 03 '13 at 14:47
0

Assuming you return array from the php (the same format that you mention in the question). Then add this to your <script>:

function both(Restaurant) {
    return Restaurant.name + ',' + Restaurant.type ; 
}
$( "#txtSearchRestaurant" ).autocomplete({
    source: 
    function( request, response ) {
        $.getJSON( "/searchRestaurant.php", function(data) {
            response(data.map(both));
        });
    }
});

Or if you need help in both PHP and javascript, first try sending array consisting of restaurant name and type as a single string element like this :

[
"McDonald's,Fast Food",
"Olive Garden,Italian",
"Manny's,Steakhouse",
"Carino's,Italian"
]

In PHP searchRestaurant.php you can do following to get the above format quickly :

$lines = file('restaurants.csv', FILE_IGNORE_NEW_LINES);
echo json_encode($lines);

In <script> add :

$( "#txtSearchRestaurant" ).autocomplete({
    source: 
    function( request, response ) {
        $.getJSON( "/searchRestaurant.php", response);
    }
});
user568109
  • 47,225
  • 17
  • 99
  • 123
  • I tried your suggested code (both the PHP and JS, but unfortunately that didn't work. Was it your intention that your suggested code should be the complete code to make the autocomplete functional? – marky Jun 03 '13 at 10:27
  • Yes, the PHP and JS example I had given was to check if autocomplete is working. I forgot to add `header('Content-type: application/json');` before you echo in your PHP. Can you check if it recieving the JSON correctly ? If you ensure the output of PHP is json like you gave in question. Then it should read the json correctly. – user568109 Jun 03 '13 at 10:58
  • I added the `header(...` line, but unfortunately that didn't do the trick. I double- and triple-checked to make sure everything is correct (per your suggestions), but it's still not working. What's more troubling is that I added a `console.log()` command before and after the `$.getJSON` line and that's not even working - yes, the element selector is correct... – marky Jun 03 '13 at 11:39
0

I think the keys in the returned array should be 'label' and 'value'.

Maybe you could replace:

$data[] = array_combine($header, $row);

by

if (preg_match("/^$term|$term/i", $row)) 
    $return[] = array('label'=>$header,'value'=>$row);

So it becomes (untested):

<?php
$header = NULL;
$return = array();
$term   = $_GET['term']; 

if (($file = fopen('restaurants.csv', 'r')) !== FALSE) {
    while (($row = fgetcsv($file, 1000, ',')) !== FALSE) {
        if(!$header)
            $header = $row;
        else
            if (preg_match("/^$term|$term/i", $row)) 
                $return[] = array('label'=>$header,'value'=>$row);
    }

fclose($file);
}

echo json_encode(array_values(array_unique($return)));
?>
Rembunator
  • 1,305
  • 7
  • 13