jQuery autocomplete has a couple of events to modify what is seen in the list and what is the desired value.
Likewise you can pass a function to the source (data source) to have more control of the filtering:
autocomplete.source
source: function (request, response) {}
In request.term
comes what to look for, response
is a callback that receives the results of the search, in this case we will send it empty if there is nothing or a list of pairs value
the code found and label
which is how this is shown in the selector, $resultados
is an empty array or with the results of the event success
.
ajax.complete dentro de autocomplete.source
complete: function (data) {
datos = ($resultados)?$resultados.map(
function(x){
return {
value: x.codigo,
label: x.codigo +
" - " + x.apellido_paterno +
" " + x.apellido_materno +
", " + x.nombre
};
}):[];
response(datos);
}
The callback response
must always be called, that is why it is in the event complete
of the ajax.
In the event success
we save the results in an array so we can bring more values associated with the search by registration:
ajax.success dentro de autocomplete.source
success: function(data){
$resultados = JSON.parse(data);
},
What we then show when selecting an item from the list:
autocomplete.onSelect
select: function( event, ui ) {
$codigo = ui.item.value;
var $detalles = $resultados.find(function(x){return x.codigo==$codigo});
$("#resultado").html(
"Código: " + $detalles['codigo'] + "<br/>" +
"Nombre: " + $detalles['nombre'] + "<br/>" +
"Apellidos: " + $detalles['apellido_paterno'] +
" " + $detalles['apellido_materno'] + "<br/>" +
"Label Mostrado: " + ui.item.label
);
}
Here there is no check of whether $resultados
exists because if there were no results, you can not select one.
Bonus: we modify the render so that it highlights the searched string
.data("ui-autocomplete")._renderItem = function (ul, item) {
var newText = String(item.label).replace(
new RegExp(this.term, "gi"),
"<span class='ui-state-highlight'>$&</span>");
return $("<li></li>")
.data("item.autocomplete", item)
.append("<div>" + newText + "</div>")
.appendTo(ul);
};
For this to work, the php must change a little to return a json with the data.
We change the echo for an array $resultados
that we return empty ... or with the results found.
buscardetallepaciente.php
$resultados = [];
if(!empty($_POST['b'])) {
...
while ($row = $result->fetch_array()) {
$codigo = $row['codigo'];
$nombre = $row['nombre'];
$ape_pa = $row['apellido_paterno'];
$ape_ma = $row['apellido_materno'];
$resultados[] = [
"codigo" => $codigo,
"nombre" => $nombre,
"apellido_paterno" => $ape_pa,
"apellido_materno" => $ape_ma,
];
}
}
echo json_encode($resultados);
It is also good to be able to show things in a way that makes it easier to choose the correct record, for this we modify the SQL a bit:
SELECT codigo, nombre, apellido_paterno, apellido_materno
FROM persona WHERE codigo LIKE ?
ORDER BY apellido_paterno, apellido_materno, nombre, codigo
LIMIT 35
We sort by Surname, Name, code and limit the results to the first 35 (a select with many elements becomes a little uncomfortable). You can return more results, sort by some field that makes more sense, etc ... see what is most convenient for the user.
Everything together would be:
// variable global para guardar los resultados
var $resultados = [];
$(function() {
$("#skills2").autocomplete({
source: function(request, response) {
consulta = request.term;
$.ajax({
type: "POST",
url: "buscardetallepaciente.php",
data: "b=" + consulta,
beforeSend: function() {
//imagen de carga
$("#resultado").html("");
},
error: function() {
// si hay error limpiamos resultados
$resultados = [];
console.log("error petición ajax");
},
success: function(data) {
// console.log("S:", data);
// si hay éxito en la consulta parseamos resultados
// éxito aquí también significa sin resultados
$resultados = JSON.parse(data);
},
complete: function(data) {
// console.log("C",data.responseText, $resultados);
// si hay resultados mapeamos los datos correspondientes
// value: el valor buscado
// label: lo que se muestra para seleccionar
datos = ($resultados) ? $resultados.map(
function(x) {
return {
value: x.codigo,
label: x.codigo +
" - " + x.apellido_paterno +
" " + x.apellido_materno +
", " + x.nombre
};
}) : [];
response(datos);
}
});
},
select: function( event, ui ) {
// console.log(ui.item);
// al seleccionar un elemento de la lista
// recuperamos los campos extra de resultados
$codigo = ui.item.value;
var $detalles = $resultados.find(function(x){return x.codigo==$codigo});
$("#resultado").html(
"Código: " + $detalles['codigo'] + "<br/>" +
"Nombre: " + $detalles['nombre'] + "<br/>" +
"Apellidos: " + $detalles['apellido_paterno'] +
" " + $detalles['apellido_materno'] + "<br/>" +
"Label Mostrado: " + ui.item.label
);
},
}).data("ui-autocomplete")._renderItem = function (ul, item) {
var newText = String(item.label).replace(
new RegExp(this.term, "gi"),
"<span class='ui-state-highlight'>$&</span>");
return $("<li></li>")
.data("item.autocomplete", item)
.append("<div>" + newText + "</div>")
.appendTo(ul);
};
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<title>autocompleit</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.css" />
</head>
<body>
<div class="panel panel-default" style="margin-left: 15px;">
<div>
<table class="table" style="margin-bottom: -1px;">
<td>
<div class="panel-heading">
<h7>Código*</h7>
</div>
</td>
<td>
<div class="panel-heading">
<h7><i>Verificación</i></h7>
</div>
</td>
</table>
<table class="table">
<td>
<center>
<input maxlength="11" type="text" required name="codigo_pac" id="skills2">
</center>
</td>
<td>
<div id="resultado"></div>
</td>
</table>
</div>
</div>
</body>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jqueryui/1.12.1/jquery-ui.min.js"></script>
</html>
and the php, I include a function to sanitize the search via WHERE x LIKE ?
:
<?php
/**
* Returns a string with backslashes before characters that need to be escaped.
* As required by MySQL and suitable for multi-byte character sets
* Characters encoded are NUL (ASCII 0), \n, \r, \, ', ", and ctrl-Z.
* In addition, the special control characters % and _ are also escaped,
* suitable for all statements, but especially suitable for 'LIKE'.
*
* @param string $string String to add slashes to
* @return $string with '\' prepended to reserved characters
*
* @author Trevor Herselman
*/
if (function_exists('mb_ereg_replace'))
{
function mb_escape(string $string)
{
return mb_ereg_replace('[\x00\x0A\x0D\x1A\x22\x25\x27\x5C\x5F]', '\source: function (request, response) {}
', $string);
}
} else {
function mb_escape(string $string)
{
return preg_replace('~[\x00\x0A\x0D\x1A\x22\x25\x27\x5C\x5F]~u', '\\ complete: function (data) {
datos = ($resultados)?$resultados.map(
function(x){
return {
value: x.codigo,
label: x.codigo +
" - " + x.apellido_paterno +
" " + x.apellido_materno +
", " + x.nombre
};
}):[];
response(datos);
}
', $string);
}
}
$resultados = [];
if(!empty($_POST['b'])) {
$con = mysqli_connect('localhost','root', 'xxxx');
mysqli_select_db($con,'central');
$param = "%".mb_escape($_POST['b'])."%";
$SQLquery =
"SELECT codigo, nombre, apellido_paterno, apellido_materno
FROM persona WHERE codigo LIKE ?
ORDER BY apellido_paterno, apellido_materno, nombre, codigo
LIMIT 35";
$stmt = $con->prepare($SQLquery);
$stmt->bind_param("s", $param);
$stmt->execute();
$result = $stmt->get_result();
while ($row = $result->fetch_array()) {
$codigo = $row['codigo'];
$nombre = $row['nombre'];
$ape_pa = $row['apellido_paterno'];
$ape_ma = $row['apellido_materno'];
$resultados[] = [
"codigo" => $codigo,
"nombre" => $nombre,
"apellido_paterno" => $ape_pa,
"apellido_materno" => $ape_ma,
];
}
}
echo json_encode($resultados);