Resumen: mostrar cómo autocompletar un campo con valores de una tabla de una base de datos MySQL; trayendo los datos con AJAX.
En este post te mostraré cómo sugerir nombres conforme el usuario escribe; trayendo los datos de MySQL con una consulta LIKE y usando fetch para traer los datos por AJAX en tiempo real.
Para lograr esto vamos a usar la librería awesomplete; cuya introducción ya vimos anteriormente. Si no la has visto, mírala para que veas cómo descargarla e incluirla.
En el servidor simplemente mostraremos un arreglo de datos que servirán para llenar la lista. Vamos a recibir un parámetro GET en la URL para la búsqueda.
Voy a usar el archivo de base de datos del tutorial de PHP con MySQL:
<?php
$contraseña = "";
$usuario = "root";
$nombre_base_de_datos = "mascotas";
try {
$bd = new PDO('mysql:host=localhost;dbname=' . $nombre_base_de_datos, $usuario, $contraseña);
$bd->query("set names utf8;");
$bd->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$bd->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$bd->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_OBJ);
return $bd;
} catch (Exception $e) {
echo "Ocurrió algo con la base de datos: " . $e->getMessage();
return null;
}
Ahora veamos el archivo que filtra los datos:
<?php
// Si no hay búsqueda, mostrar un arreglo vacío y salir
if (empty($_GET["busqueda"])) {
echo "[]";
exit;
}
$bd = include_once "bd.php";
$busqueda = $_GET["busqueda"];
$sentencia = $bd->prepare("select * from mascotas where nombre like ?");
$sentencia->execute(["%$busqueda%"]);
$mascotas = $sentencia->fetchAll(PDO::FETCH_OBJ);
echo json_encode($mascotas);
Lo que haremos será buscar en una base de datos de mascotas; si quieres puedes insertarlas con lo siguiente:
-- MySQL dump 10.16 Distrib 10.1.31-MariaDB, for Win32 (AMD64)
--
-- Host: localhost Database: mascotas
-- ------------------------------------------------------
-- Server version 10.1.31-MariaDB
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
/*!40101 SET NAMES utf8 */;
/*!40103 SET @OLD_TIME_ZONE=@@TIME_ZONE */;
/*!40103 SET TIME_ZONE='+00:00' */;
/*!40014 SET @OLD_UNIQUE_CHECKS=@@UNIQUE_CHECKS, UNIQUE_CHECKS=0 */;
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */;
/*!40101 SET @OLD_SQL_MODE=@@SQL_MODE, SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */;
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */;
--
-- Table structure for table `mascotas`
--
DROP TABLE IF EXISTS `mascotas`;
/*!40101 SET @saved_cs_client = @@character_set_client */;
/*!40101 SET character_set_client = utf8 */;
CREATE TABLE `mascotas` (
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
`nombre` varchar(255) NOT NULL,
`raza` varchar(255) NOT NULL,
`edad` tinyint(4) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1;
/*!40101 SET character_set_client = @saved_cs_client */;
--
-- Dumping data for table `mascotas`
--
LOCK TABLES `mascotas` WRITE;
/*!40000 ALTER TABLE `mascotas` DISABLE KEYS */;
INSERT INTO `mascotas` VALUES (1,'Maggie','Chihuaha',10),(2,'Panque','Ninguna',1),(3,'Guayaba','Ninguna',2),(4,'Cocoa','Ninguna',2);
/*!40000 ALTER TABLE `mascotas` ENABLE KEYS */;
UNLOCK TABLES;
/*!40103 SET TIME_ZONE=@OLD_TIME_ZONE */;
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */;
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */;
/*!40014 SET UNIQUE_CHECKS=@OLD_UNIQUE_CHECKS */;
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */;
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */;
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */;
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */;
-- Dump completed on 2019-12-03 15:46:00
Al consultar con, por ejemplo, la letra a tenemos esto:
Aunque el autocompletado ya filtra los datos, siempre es importante tener un límite de datos. Imagina si fueran millones de registros, sería mejor buscar los que coinciden en el servidor, que buscarlos del lado del cliente.
En el HTML de nuestro input
para autocompletar importamos los estilos, el script de awesomplete y nuestro propio script para el funcionamiento:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Autocompletado con AJAX y PHP</title>
<link rel="stylesheet" href="awesomplete.base.css">
<link rel="stylesheet" href="awesomplete.theme.css">
</head>
<body>
<h1>Probando Autocompletado</h1>
<input type="text" id="nombre" autocomplete="off" placeholder="Escribe un nombre">
<script src="awesomplete.min.js"></script>
<script src="script.js"></script>
</body>
</html>
Lo único destacable es que el input
tiene el id nombre
y el autocomplete desactivado.
Finalmente veamos el script de JavaScript. Primero obtenemos una referencia al input
con querySelector, y creamos un objeto de tipo Awesomplete
; le pasamos el input como primer argumento, y como segundo argumento un objeto de configuraciones.
En el objeto de configuraciones indicamos las sugerencias, que son un arreglo vacío al principio. También indicamos el mínimo de caracteres a 1.
document.addEventListener("DOMContentLoaded", () => {
// El elemento que tendrá el autocompletado
const $inputNombre = document.querySelector("#nombre");
let ac = new Awesomplete($inputNombre, {
list: [], // Por defecto es una lista vacía, hasta que se comienza a escribir
minChars: 1, // Cuántos caracteres escribir para autocompletar
});
// Esta función filtra los datos y refresca el autocompletado
const refrescarLista = () => {
let valorDelInput = $inputNombre.value;
if (!valorDelInput) return; // Detener si no hay valor
// Buscar nombres de la base de datos con PHP
fetch("./nombres.php?busqueda=" + valorDelInput)
.then(r => r.json())
.then(mascotas => {
// Mapeamos, ya que se requiere label y value
ac.list = mascotas.map(mascota => ({
label: mascota.nombre, // Lo que aparece al buscar
value: mascota.id, // El valor que se pone en el input
}));
});
};
// Agregar un listener para cuando se cambie el contenido; en el mismo se refresca la lista
$inputNombre.addEventListener("input", () => {
refrescarLista();
});
});
En la línea 13 defino la función que refresca la lista, la cual obtendrá el valor del input
(es decir, lo que el usuario haya escrito); si hay algo escrito entonces se realiza una petición con fetch y tendremos el arreglo de MySQL que mostré anteriormente.
Después de eso, asignamos el arreglo a ac.list
(recuerda que ac
es un objeto de tipo Awesomplete
) pero antes de eso lo mapeamos, pues Awesomplete
requiere un arreglo plano, o un arreglo de objetos con la clave label
(que es lo que se muestra) y value
, que es lo que se coloca en el input
al seleccionar una opción.
Finalmente agregamos un listener al input
, para que cuando el usuario escriba se refresque la lista. Al final obtenemos el siguiente resultado:
Por cierto, si quieres el evento cuando se selecciona el valor del autocompletado puedes agregar un listener al input. El evento que dice que se ha seleccionado (ya sea con el mouse o usando el teclado) se llama awesomplete-selectcomplete
.
$inputNombre.addEventListener("awesomplete-selectcomplete", function() {
console.log("Se ha seleccionado un elemento de la lista");
});
Si quisieras que cuando se haga la selección, en lugar del id se pusiera el nombre, al mapear el arreglo coloca el nombre en el value
.
He colocado el código completo en GitHub. Puedes verlo aquí.
También puedes ver más sobre los eventos de awesomplete en su página oficial.
Hoy te voy a presentar un creador de credenciales que acabo de programar y que…
Ya te enseñé cómo convertir una aplicación web de Vue 3 en una PWA. Al…
En este artículo voy a documentar la arquitectura que yo utilizo al trabajar con WebAssembly…
En un artículo anterior te enseñé a crear un PWA. Al final, cualquier aplicación que…
Al usar Comlink para trabajar con los workers usando JavaScript me han aparecido algunos errores…
En este artículo te voy a enseñar cómo usar un "top level await" esperando a…
Esta web usa cookies.
Ver comentarios
Hola, espero me puedas responder ya que es un hilo bastante viejo, pero estoy haciendo un sistema de ventas y este autocompletar me viene perfecto para buscar los productos en el input, solo queria preguntar que deberia modificar para que al seleccionar uno de los datos el formulario me envie los datos al seleccionar o hacer click en este?
Gracias de antemano.
Hola. Gracias por sus comentarios. Si tiene alguna consulta, solicitud de creación de un programa o solicitud de cambio de software estoy para servirle en https://parzibyte.me/#contacto
Saludos!
Comparto una alternativa al archivo que filtra los datos, esperando tus comentarios y opinión sobre dicha solución, de ser posible:
include('conexion.php');
$conn = OpenCon();
$busqueda = $_GET["nombre"];
$miArreglo = array();
$sql = "SELECT * FROM mascotas where nombre like '%$busqueda%' ";
if (mysqli_query($conn, $sql)) {
$result = mysqli_query($conn, $sql);
while($row = $result->fetch_assoc()) {
$miarreglo[] = $row;
}
echo json_encode($miArreglo);
} else {
echo "Error: " . $sql . "" . mysqli_error($conn);
}
CloseCon($conn);
}
conexion.php ------
function OpenCon(){
$dbhost = "localhost";
$dbuser = "root";
$dbpass = "";
$db = "nombredb";
$conn = new mysqli($dbhost, $dbuser, $dbpass,$db) or die("Falló: %s\n". $conn -> error);
return $conn;
}
function closeCon($conn){
$conn->close();
}
Muchas gracias por compartir tu conocimiento.
¡Saludos!