views:

56

answers:

1

I'm creating my own recipe box using php/mysql and one part I'm stuck on is actually creating the recipes, specifically selecting the ingredients.

What I wanted to do instead is have a auto-complete search box where I can type out names of the ingredients, have the results drop down right below, and click the ones I'm looking for. After clicking the ingredient, it'll be listed below the search box with an input to put quantity and an "x" to delete if needed. This of course would grow depending on how many ingredients the recipe requires. At the end, I would just take the data and do an insert into my database.

I've seen a lot of AJAX tutorials on getting the auto-complete search box functionality, but nothing tying it to the value selection. The best example of what I'm going for can be found at http://supercook.com. They have it so you can search for recipes.

Any suggestions or online resources?

Thanks!

+2  A: 

Hello Cass, you asked a great question. Below I've written a short example to get you started. Just save it as ingredients.php and it should work. Of course, you'll need to add your database connection and query to give it real data. I've used the jQuery library because it makes the Javascript part a lot easier.

<?php

// connect to database here

if (isset($_POST['q'])) {
    if (trim($_POST['q']) === '') die('[]');
    // $q = mysql_real_escape_string($_POST['q']);
    // run a query like: "SELECT id, name FROM ingredients WHERE name LIKE '{$q}%'"
    // and put the result in the $result array.
    // This is sample data:
    $result = array(
        array('id' => 71, 'name' => 'apple'),
        array('id' => 3, 'name' => 'anchovies'),
        array('id' => 230, 'name' => 'artichoke'),
        );

    if (function_exists('json_encode')) die(json_encode($result));
    else {
        $escaped = array();
        foreach ($result as $r) $escaped[] = str_replace(array('\\', '"'), array('\\\\', '\"'), $r);
        die('["'.join('","', $escaped).'"]');
    }
}

$data = array();
if (isset($_POST['ingredients'])) {
    foreach ($_POST['ingredients'] as $i => $ingredient) {
        $data[] = array(
            'ingredient' => $ingredient,
            'quantity' => $_POST['quantities'][$i],
            );
    }
    // save data to the database here (or inside the foreach loop above)
}

?>
<html><head></head><body>
<style>
    #wrap { position: relative }
    #pop {
        position: absolute;
        border: 1px solid black;
        background-color: white;
        display: none;
    }
</style>

<?php if (count($data)): ?>
<h3>Saved:</h3>
<pre><?php print_r($data) ?></pre>
<?php endif; ?>

<div id="wrap">
    <input id="adder" />
    <div id="pop"></div>
</div>
<form method="post">
    Ingredients:<br />
    <div id="recipe"></div>
    <input type="submit" value="Save" />
</form>

<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.4.2/jquery.min.js"&gt;&lt;/script&gt;
<script>
    var last_query = '';
    jQuery(function() {
        jQuery('#adder').val('').keyup(function() {
            var query = jQuery(this).val();
            if (query != last_query) jQuery.post('ingredients.php', {q: query}, function(data) {
                var p = jQuery('#pop').html('').show();
                for (var i=0; i<data.length; i++) {
                    p.append(jQuery('<p>'+data[i].name+'</p>').bind('click', { ingredient: data[i] }, function(e) {
                        add_ingredient(e.data.ingredient);
                        jQuery('#pop').hide();
                        jQuery('#adder').val('');
                    }));
                }
            }, 'json');
            else jQuery('#pop').show();
            last_query = query;
        });
    });
    function add_ingredient(data) {
        console.log(data);
        var ingredient = jQuery('<div> <input name="quantities[]" size="2" /> '+data.name
            + '<input type="hidden" name="ingredients[]" value="'+data.id+'" /></div>');
        var remover = jQuery('<span>X</span>').click(function() {
            jQuery(this).parent().remove();
        });
        jQuery('#recipe').append(ingredient.prepend(remover));
    }
</script>
</body></html>
Mark Eirich
Wow, wasn't expecting all that...awesome! Though I am having some trouble. Again, I'm a noob.Should this be able to run as-is? I just wanted to see that this would work with the sample data you put in, but it's not. I get this notice:"Notice: Undefined index: q in C:\wamp\www\recipe\test.php on line 5"Also, no results box popping under the input field when I start typing the sample data.Are there any prereqs for this to work?
Cass
Yes, it was supposed to run as-is, if you name the file ingredients.php. I just now edited the code to fix the "undefined index" error, but I don't think that would be keeping it from working. One likely possibility is that you don't have the JSON module installed, so the json_encode() function isn't working. To check this, put this line in a PHP file: `echo function_exists('json_encode')? 'have json' : 'do not have json';` If you don't have it, try to install it. If you have trouble installing it, let me know and I'll rewrite the code so it doesn't require it.
Mark Eirich
If you're using the latest version of wamp from www.wampserver.com, then theoretically you already have JSON support. Are you getting any other error messages? Try checking if you have any Javascript errors as well. If you're using Firefox, the Firebug extension can help you debug. However, it all works perfectly on my server and browser.... Sorry it isn't working for you!
Mark Eirich
Okay, it's now edited so that it doesn't require json_encode.
Mark Eirich
Oh, I'm silly for not noticing before now that you had renamed the file test.php... **you need to rename the file ingredients.php** or replace `jQuery.post('ingredients.php'...` with `jQuery.post('test.php'...` or whatever you named the file.
Mark Eirich
Man, you are freaking amazing. Just tried it out again and IT WORKED! I started playing around with using my actual data in the database and got that working too! Thank you so much!!!
Cass
No problem at all. I'd love to see what you are building. I've wanted to build an online recipe box myself but not badly enough to get started. At one point I worked on parsing and converting ingredient amounts, though. I wish you the best.
Mark Eirich
A quick follow up question. In the hidden input, the name of the ingredient will be the value that will be passed. What I would prefer to have is the ingredient ID that I set in the ingredient table. Is this possible? Otherwise, I think the name can be done.
Cass
Hey Cass, I edited the code to save ingredient ID instead of name, display saved ingredients, and prevent duplicate search queries. If you need more help, it may be better to contact me directly at http://markeirich.com/contact so we don't make such a mess here. :-P
Mark Eirich
Thank you. I will try to use your class later too.
Kirzilla