Faire un champ texte de formulaire pour retourner plusieurs valeurs

2014-02-26 0 Par seuf

Voici une petite astuce qui m’a bien servi l’autre jour : Comment faire un champ de formulaire de type texte, et mettre plusieurs données dedans (genre liste de contacts, tags, etc..)

Tout d’abord, côté HTML (dans l’exemple j’utilise Twig comme moteur de templates), on va créer une liste dans laquelle on va mettre un champ input :

<label for="contacts">Contacts :</label>
<div class="value" style="margin:0px">
    <ul id="contacts_list" class="holder">
        <li class="input-text"><input type="text" value="" id="contacts_search" /></li>
        {% for c in f.contacts %}
            <li class="bit-box" value="{{ c.id }}" id="{{ c.id }}">
                <input type="hidden" name="contacts[]" value="{{ c.id }}" />{{ c.nom }} {{ c.prenom }}
                <img id="close-{{ c.id }}" class="closebutton" src="images/close.gif"></img>
            </li>
        {% endfor %}
    </ul>
</div>

Ensuite, un peut de javascript / jquery UI pour avoir de l’autocompletion lorsque l’on tape dans le champ input :

<script type="text/javascript" src="js/jquery-ui-1.10.4.custom.min.js"></script>
<script>
$(document).ready(function() {
    $('#contacts_search').autocomplete({
        source: function(req, add) {
            $.getJSON("ws/search_contacts.php", { search: req.term }, function(data) {
                //create array for response objects
                var contacts = [];
                //process response
                $.each(data, function(i, val){
                    contacts.push({ label: val.nom+' '+val.prenom, id: val.id, value: val.id });
                });
                add(contacts);
            });
        },
        minLength: 2,
        delay: 500,
        focus : function(event, ui) {
            this.value = ui.item.label;
            event.preventDefault();
        },
        select: function(event, ui) {
            $('#contacts_list').append('<li id="contact-'+ui.item.id+'" class="bit-box" value="'+ui.item.id+'"><input type="hidden" name="contacts[]" value="'+ui.item.id+'" />'+ui.item.label+'<img src="images/close.gif" id="close-'+ui.item.id+'" class="closebutton" /></li>');
            this.value= "";
            event.preventDefault();
        }
    });
});
</script>

Encore du jquery pour enlver des elements de la liste quand on clique sur la petite croix

<script>
$(document).ready(function() {
    $(document).on('click', ".closebutton", function() {
        var liId = $(this).parent("li").attr("id");
        $('#'+liId).remove();
    });
});
</script>

Le petit pour de code php appelé en ajax :

<?php

$conf = parse_ini_file('../config.ini');
try {
    $dbh = new PDO($conf['db_type'].':host='.$conf['db_host'].';dbname='.$conf['db_name'].";port=".$conf['db_port'], $conf['db_user'], $conf['db_pass']);
} catch(PDOException $e) {
    echo json_encode(array('error' => $e->getMessage()) );
    exit;
}
$dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

$contacts = array();
foreach ($dbh->query("SELECT * FROM contacts ORDER BY nom") as $row) {
    $contacts[] = $row;
}

$search = array();
if (isset($_GET['search'])) {
     foreach ($contacts as $c) {
        $pattern = "/".trim($_GET['search'])."/i";
        if (preg_match($pattern, $c['nom']) or preg_match($pattern, $c['prenom'])) {
            $search[$c['id']] = $c;
        }
    }
}

echo json_encode($search);

?>

Et enfin, côté serveur, y’a plus qu’a récupérer les infos dans un tableau « contacts », et les insérer dans la table de relation objet / contacts :

$sth = $dbh->prepare("INSERT INTO contacts_object (id_object, id_contact) values (?, ?)");
if (isset($_POST['contacts'])) {
    $contacts = $_POST['contacts'];
    $id_object = $_POST['id'];
    try {
        foreach ($contacts as $c) {
            $sth->execute(array($id_object, $c));
        }
    } catch (PDOException $e) {
        $error .= "Erreur Replace : ".$e->getMessage();
    }
}

Ah, j’allais oublier ! Un peut de CSS pour que la liste apparaisse bien comme il faut :

ul.holder {
    margin: 5px;
    border: 1px solid rgb(153, 153, 153);
    overflow: hidden;
    height: auto !important;
    list-style:none;
    padding: 0px 1px 0px;
}

ul.holder li.bit-box {
    border-radius: 6px;
    border: 1px solid rgb(202, 216, 243);
    background: none repeat scroll 0% 0% rgb(222, 231, 248);
    padding-right: 15px;
    position: relative;
    padding: 1px 5px 1px;
}

ul.holder input {
    width: 250px;
    margin: 0px;
    border: medium none;
    outline: 0px none;
    padding: 3px 0px 2px;
}

.ui-helper-hidden-accessible { display:none; }
.ui-corner-all {
    list-style:none;
    background: white;
}
.ui-corner-all a {
    text-decoration: none;
    color:black;
}

.closebutton {
    position: absolute;
    right: 4px;
    top: 5px;
    display: block;
    width: 7px;
    height: 7px;
    font-size: 1px;
    cursor: pointer;
}

Et voila !