Lenguaje PHP

Buscador Vanilla JavaScript en etiqueta SELECT

Esta es una publicación más de la biblioteca Bootstrap 5 con JavaScript puro y, en esta publicación, le mostraremos cómo agregar un filtro de cuadro de búsqueda en el cuadro desplegable de selección de Bootstrap 5 usando JavaScript.

Buscador Vanilla JavaScript en etiqueta SELECT

En este tutorial lograremos incorporar una búsqueda o filtro en la etiqueta SELECT haciendo uso de un cuadro desplegable de selección de Bootstrap 5 usando JavaScript. Entonces, con la ayuda de este tutorial, puede crear el cuadro de selección de búsqueda que se puede buscar en Bootstrap 5 usando JavaScript.

¿Qué recursos se usará para el ejemplo de buscador en SELECT?

Básicamente usaremos recursos que detallaremos a continuación:

  • Lenguaje HTML5
  • PHP para conexión con MySQL
  • Vanilla JavaScript Framework
  • MySQL gestor de base de datos
  • Framework de estilos BootStrap 5

Todos estos lenguajes interactúan entre sí para agregar una funcionalidad de búsqueda en Bootstrap 5. Además, la búsqueda de seleccione las opciones desplegables usando Vanilla JavaScript.

En un artículo anterior vimos una búsqueda de etiqueta select usando JavaScript puro con el framework Bootstrap 5.

También hemos implementado un buscador en SELECT usando la librería SELECT2. En esta publicación, no hemos utilizado ningún complemento de jQuery para convertir el menú desplegable simple de Bootstrap 5 en el menú desplegable Avanzado con filtro de búsqueda.

Hemos usado la biblioteca dSelect de JavaScript puro para crear un cuadro de selección con la opción de búsqueda en la biblioteca Bootstrap 5.

Estructura de buscador select con Vanilla

A continuación, puede encontrar el código fuente completo de Cómo crear el menú desplegable de selección Bootstrap 5 con el cuadro de búsqueda usando JavaScript con PHP y la base de datos MySQL.

Base de datos

Para crear y alimentar un cuadro de selección desplegable dinámico, primero necesitamos datos de una base de datos, Por lo tanto,  para datos dinámicos, tenemos que ejecutar el siguiente script .sql en su base de datos y este script creará la tabla sql_paises con datos de muestra en su base de datos local.

Este script contiene 245 países como ejemplo con 4 campos y lo pueden copiar a continuación.

CREATE TABLE `sql_paises` (
`id` int(11) NOT NULL,
`pais_codigo` varchar(2) COLLATE utf8mb4_unicode_ci DEFAULT '',
`pais_nombre` varchar(120) COLLATE utf8mb4_unicode_ci DEFAULT '',
`fecha_creacion` timestamp NOT NULL DEFAULT current_timestamp() ON UPDATE current_timestamp()
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;


INSERT INTO `sql_paises` (`id`, `pais_codigo`, `pais_nombre`, `fecha_creacion`) VALUES
(1, 'AF', 'Afghanistan', '2023-09-28 23:50:46'),
(2, 'AL', 'Albania', '2023-09-28 23:50:46'),
(3, 'DZ', 'Algeria', '2023-09-28 23:50:46'),
(4, 'DS', 'American Samoa', '2023-09-28 23:50:46'),
(5, 'AD', 'Andorra', '2023-09-28 23:50:46'),
(6, 'AO', 'Angola', '2023-09-28 23:50:46'),
(7, 'AI', 'Anguilla', '2023-09-28 23:50:46'),
(8, 'AQ', 'Antarctica', '2023-09-28 23:50:46'),
(9, 'AG', 'Antigua and Barbuda', '2023-09-28 23:50:46'),
(10, 'AR', 'Argentina', '2023-09-28 23:50:46'),
(11, 'AM', 'Armenia', '2023-09-28 23:50:46'),
(12, 'AW', 'Aruba', '2023-09-28 23:50:46'),
(13, 'AU', 'Australia', '2023-09-28 23:50:46'),
(14, 'AT', 'Austria', '2023-09-28 23:50:46'),
(15, 'AZ', 'Azerbaijan', '2023-09-28 23:50:46'),
(16, 'BS', 'Bahamas', '2023-09-28 23:50:46'),
(17, 'BH', 'Bahrain', '2023-09-28 23:50:46'),
(18, 'BD', 'Bangladesh', '2023-09-28 23:50:46'),
(19, 'BB', 'Barbados', '2023-09-28 23:50:46'),
(20, 'BY', 'Belarus', '2023-09-28 23:50:46'),
(21, 'BE', 'Belgium', '2023-09-28 23:50:46'),
(22, 'BZ', 'Belize', '2023-09-28 23:50:46'),
(23, 'BJ', 'Benin', '2023-09-28 23:50:46'),
(24, 'BM', 'Bermuda', '2023-09-28 23:50:46'),
(25, 'BT', 'Bhutan', '2023-09-28 23:50:46'),
(26, 'BO', 'Bolivia', '2023-09-28 23:50:46'),
(27, 'BA', 'Bosnia and Herzegovina', '2023-09-28 23:50:46'),
(28, 'BW', 'Botswana', '2023-09-28 23:50:46'),
(29, 'BV', 'Bouvet Island', '2023-09-28 23:50:46'),
(30, 'BR', 'Brazil', '2023-09-28 23:50:46'),
(31, 'IO', 'British Indian Ocean Territory', '2023-09-28 23:50:46'),
(32, 'BN', 'Brunei Darussalam', '2023-09-28 23:50:46'),
(33, 'BG', 'Bulgaria', '2023-09-28 23:50:46'),
(34, 'BF', 'Burkina Faso', '2023-09-28 23:50:46'),
(35, 'BI', 'Burundi', '2023-09-28 23:50:46'),
(36, 'KH', 'Cambodia', '2023-09-28 23:50:46'),
(37, 'CM', 'Cameroon', '2023-09-28 23:50:46'),
(38, 'CA', 'Canada', '2023-09-28 23:50:46'),
(39, 'CV', 'Cape Verde', '2023-09-28 23:50:46'),
(40, 'KY', 'Cayman Islands', '2023-09-28 23:50:46'),
(41, 'CF', 'Central African Republic', '2023-09-28 23:50:46'),
(42, 'TD', 'Chad', '2023-09-28 23:50:46'),
(43, 'CL', 'Chile', '2023-09-28 23:50:46'),
(44, 'CN', 'China', '2023-09-28 23:50:46'),
(45, 'CX', 'Christmas Island', '2023-09-28 23:50:46'),
(46, 'CC', 'Cocos (Keeling) Islands', '2023-09-28 23:50:46'),
(47, 'CO', 'Colombia', '2023-09-28 23:50:46'),
(48, 'KM', 'Comoros', '2023-09-28 23:50:46'),
(49, 'CG', 'Congo', '2023-09-28 23:50:46'),
(50, 'CK', 'Cook Islands', '2023-09-28 23:50:46'),
(51, 'CR', 'Costa Rica', '2023-09-28 23:50:46'),
(52, 'HR', 'Croatia (Hrvatska)', '2023-09-28 23:50:46'),
(53, 'CU', 'Cuba', '2023-09-28 23:50:46'),
(54, 'CY', 'Cyprus', '2023-09-28 23:50:46'),
(55, 'CZ', 'Czech Republic', '2023-09-28 23:50:46'),
(56, 'DK', 'Denmark', '2023-09-28 23:50:46'),
(57, 'DJ', 'Djibouti', '2023-09-28 23:50:46'),
(58, 'DM', 'Dominica', '2023-09-28 23:50:46'),
(59, 'DO', 'Dominican Republic', '2023-09-28 23:50:46'),
(60, 'TP', 'East Timor', '2023-09-28 23:50:46'),
(61, 'EC', 'Ecuador', '2023-09-28 23:50:46'),
(62, 'EG', 'Egypt', '2023-09-28 23:50:46'),
(63, 'SV', 'El Salvador', '2023-09-28 23:50:46'),
(64, 'GQ', 'Equatorial Guinea', '2023-09-28 23:50:46'),
(65, 'ER', 'Eritrea', '2023-09-28 23:50:46'),
(66, 'EE', 'Estonia', '2023-09-28 23:50:46'),
(67, 'ET', 'Ethiopia', '2023-09-28 23:50:46'),
(68, 'FK', 'Falkland Islands (Malvinas)', '2023-09-28 23:50:46'),
(69, 'FO', 'Faroe Islands', '2023-09-28 23:50:46'),
(70, 'FJ', 'Fiji', '2023-09-28 23:50:46'),
(71, 'FI', 'Finland', '2023-09-28 23:50:46'),
(72, 'FR', 'France', '2023-09-28 23:50:46'),
(73, 'FX', 'France, Metropolitan', '2023-09-28 23:50:46'),
(74, 'GF', 'French Guiana', '2023-09-28 23:50:46'),
(75, 'PF', 'French Polynesia', '2023-09-28 23:50:46'),
(76, 'TF', 'French Southern Territories', '2023-09-28 23:50:46'),
(77, 'GA', 'Gabon', '2023-09-28 23:50:46'),
(78, 'GM', 'Gambia', '2023-09-28 23:50:46'),
(79, 'GE', 'Georgia', '2023-09-28 23:50:46'),
(80, 'DE', 'Germany', '2023-09-28 23:50:46'),
(81, 'GH', 'Ghana', '2023-09-28 23:50:46'),
(82, 'GI', 'Gibraltar', '2023-09-28 23:50:46'),
(83, 'GK', 'Guernsey', '2023-09-28 23:50:46'),
(84, 'GR', 'Greece', '2023-09-28 23:50:46'),
(85, 'GL', 'Greenland', '2023-09-28 23:50:46'),
(86, 'GD', 'Grenada', '2023-09-28 23:50:46'),
(87, 'GP', 'Guadeloupe', '2023-09-28 23:50:46'),
(88, 'GU', 'Guam', '2023-09-28 23:50:46'),
(89, 'GT', 'Guatemala', '2023-09-28 23:50:46'),
(90, 'GN', 'Guinea', '2023-09-28 23:50:46'),
(91, 'GW', 'Guinea-Bissau', '2023-09-28 23:50:46'),
(92, 'GY', 'Guyana', '2023-09-28 23:50:46'),
(93, 'HT', 'Haiti', '2023-09-28 23:50:46'),
(94, 'HM', 'Heard and Mc Donald Islands', '2023-09-28 23:50:46'),
(95, 'HN', 'Honduras', '2023-09-28 23:50:46'),
(96, 'HK', 'Hong Kong', '2023-09-28 23:50:46'),
(97, 'HU', 'Hungary', '2023-09-28 23:50:46'),
(98, 'IS', 'Iceland', '2023-09-28 23:50:46'),
(99, 'IN', 'India', '2023-09-28 23:50:46'),
(100, 'IM', 'Isle of Man', '2023-09-28 23:50:46'),
(101, 'ID', 'Indonesia', '2023-09-28 23:50:46'),
(102, 'IR', 'Iran (Islamic Republic of)', '2023-09-28 23:50:46'),
(103, 'IQ', 'Iraq', '2023-09-28 23:50:46'),
(104, 'IE', 'Ireland', '2023-09-28 23:50:46'),
(105, 'IL', 'Israel', '2023-09-28 23:50:46'),
(106, 'IT', 'Italy', '2023-09-28 23:50:46'),
(107, 'CI', 'Ivory Coast', '2023-09-28 23:50:46'),
(108, 'JE', 'Jersey', '2023-09-28 23:50:46'),
(109, 'JM', 'Jamaica', '2023-09-28 23:50:46'),
(110, 'JP', 'Japan', '2023-09-28 23:50:46'),
(111, 'JO', 'Jordan', '2023-09-28 23:50:46'),
(112, 'KZ', 'Kazakhstan', '2023-09-28 23:50:46'),
(113, 'KE', 'Kenya', '2023-09-28 23:50:46'),
(114, 'KI', 'Kiribati', '2023-09-28 23:50:46'),
(115, 'KP', 'Korea, Democratic People\'s Republic of', '2023-09-28 23:50:46'),
(116, 'KR', 'Korea, Republic of', '2023-09-28 23:50:46'),
(117, 'XK', 'Kosovo', '2023-09-28 23:50:46'),
(118, 'KW', 'Kuwait', '2023-09-28 23:50:46'),
(119, 'KG', 'Kyrgyzstan', '2023-09-28 23:50:46'),
(120, 'LA', 'Lao People\'s Democratic Republic', '2023-09-28 23:50:46'),
(121, 'LV', 'Latvia', '2023-09-28 23:50:46'),
(122, 'LB', 'Lebanon', '2023-09-28 23:50:46'),
(123, 'LS', 'Lesotho', '2023-09-28 23:50:46'),
(124, 'LR', 'Liberia', '2023-09-28 23:50:46'),
(125, 'LY', 'Libyan Arab Jamahiriya', '2023-09-28 23:50:46'),
(126, 'LI', 'Liechtenstein', '2023-09-28 23:50:46'),
(127, 'LT', 'Lithuania', '2023-09-28 23:50:46'),
(128, 'LU', 'Luxembourg', '2023-09-28 23:50:46'),
(129, 'MO', 'Macau', '2023-09-28 23:50:46'),
(130, 'MK', 'Macedonia', '2023-09-28 23:50:46'),
(131, 'MG', 'Madagascar', '2023-09-28 23:50:46'),
(132, 'MW', 'Malawi', '2023-09-28 23:50:46'),
(133, 'MY', 'Malaysia', '2023-09-28 23:50:46'),
(134, 'MV', 'Maldives', '2023-09-28 23:50:46'),
(135, 'ML', 'Mali', '2023-09-28 23:50:46'),
(136, 'MT', 'Malta', '2023-09-28 23:50:46'),
(137, 'MH', 'Marshall Islands', '2023-09-28 23:50:46'),
(138, 'MQ', 'Martinique', '2023-09-28 23:50:46'),
(139, 'MR', 'Mauritania', '2023-09-28 23:50:46'),
(140, 'MU', 'Mauritius', '2023-09-28 23:50:46'),
(141, 'TY', 'Mayotte', '2023-09-28 23:50:46'),
(142, 'MX', 'Mexico', '2023-09-28 23:50:46'),
(143, 'FM', 'Micronesia, Federated States of', '2023-09-28 23:50:46'),
(144, 'MD', 'Moldova, Republic of', '2023-09-28 23:50:46'),
(145, 'MC', 'Monaco', '2023-09-28 23:50:46'),
(146, 'MN', 'Mongolia', '2023-09-28 23:50:46'),
(147, 'ME', 'Montenegro', '2023-09-28 23:50:46'),
(148, 'MS', 'Montserrat', '2023-09-28 23:50:46'),
(149, 'MA', 'Morocco', '2023-09-28 23:50:46'),
(150, 'MZ', 'Mozambique', '2023-09-28 23:50:46'),
(151, 'MM', 'Myanmar', '2023-09-28 23:50:46'),
(152, 'NA', 'Namibia', '2023-09-28 23:50:46'),
(153, 'NR', 'Nauru', '2023-09-28 23:50:46'),
(154, 'NP', 'Nepal', '2023-09-28 23:50:46'),
(155, 'NL', 'Netherlands', '2023-09-28 23:50:46'),
(156, 'AN', 'Netherlands Antilles', '2023-09-28 23:50:46'),
(157, 'NC', 'New Caledonia', '2023-09-28 23:50:46'),
(158, 'NZ', 'New Zealand', '2023-09-28 23:50:46'),
(159, 'NI', 'Nicaragua', '2023-09-28 23:50:46'),
(160, 'NE', 'Niger', '2023-09-28 23:50:46'),
(161, 'NG', 'Nigeria', '2023-09-28 23:50:46'),
(162, 'NU', 'Niue', '2023-09-28 23:50:46'),
(163, 'NF', 'Norfolk Island', '2023-09-28 23:50:46'),
(164, 'MP', 'Northern Mariana Islands', '2023-09-28 23:50:46'),
(165, 'NO', 'Norway', '2023-09-28 23:50:46'),
(166, 'OM', 'Oman', '2023-09-28 23:50:46'),
(167, 'PK', 'Pakistan', '2023-09-28 23:50:46'),
(168, 'PW', 'Palau', '2023-09-28 23:50:46'),
(169, 'PS', 'Palestine', '2023-09-28 23:50:46'),
(170, 'PA', 'Panama', '2023-09-28 23:50:46'),
(171, 'PG', 'Papua New Guinea', '2023-09-28 23:50:46'),
(172, 'PY', 'Paraguay', '2023-09-28 23:50:46'),
(173, 'PE', 'Peru', '2023-09-28 23:50:46'),
(174, 'PH', 'Philippines', '2023-09-28 23:50:46'),
(175, 'PN', 'Pitcairn', '2023-09-28 23:50:46'),
(176, 'PL', 'Poland', '2023-09-28 23:50:46'),
(177, 'PT', 'Portugal', '2023-09-28 23:50:46'),
(178, 'PR', 'Puerto Rico', '2023-09-28 23:50:46'),
(179, 'QA', 'Qatar', '2023-09-28 23:50:46'),
(180, 'RE', 'Reunion', '2023-09-28 23:50:46'),
(181, 'RO', 'Romania', '2023-09-28 23:50:46'),
(182, 'RU', 'Russian Federation', '2023-09-28 23:50:46'),
(183, 'RW', 'Rwanda', '2023-09-28 23:50:46'),
(184, 'KN', 'Saint Kitts and Nevis', '2023-09-28 23:50:46'),
(185, 'LC', 'Saint Lucia', '2023-09-28 23:50:46'),
(186, 'VC', 'Saint Vincent and the Grenadines', '2023-09-28 23:50:46'),
(187, 'WS', 'Samoa', '2023-09-28 23:50:46'),
(188, 'SM', 'San Marino', '2023-09-28 23:50:46'),
(189, 'ST', 'Sao Tome and Principe', '2023-09-28 23:50:46'),
(190, 'SA', 'Saudi Arabia', '2023-09-28 23:50:46'),
(191, 'SN', 'Senegal', '2023-09-28 23:50:46'),
(192, 'RS', 'Serbia', '2023-09-28 23:50:46'),
(193, 'SC', 'Seychelles', '2023-09-28 23:50:46'),
(194, 'SL', 'Sierra Leone', '2023-09-28 23:50:46'),
(195, 'SG', 'Singapore', '2023-09-28 23:50:46'),
(196, 'SK', 'Slovakia', '2023-09-28 23:50:46'),
(197, 'SI', 'Slovenia', '2023-09-28 23:50:46'),
(198, 'SB', 'Solomon Islands', '2023-09-28 23:50:46'),
(199, 'SO', 'Somalia', '2023-09-28 23:50:46'),
(200, 'ZA', 'South Africa', '2023-09-28 23:50:46'),
(201, 'GS', 'South Georgia South Sandwich Islands', '2023-09-28 23:50:46'),
(202, 'ES', 'Spain', '2023-09-28 23:50:46'),
(203, 'LK', 'Sri Lanka', '2023-09-28 23:50:46'),
(204, 'SH', 'St. Helena', '2023-09-28 23:50:46'),
(205, 'PM', 'St. Pierre and Miquelon', '2023-09-28 23:50:46'),
(206, 'SD', 'Sudan', '2023-09-28 23:50:46'),
(207, 'SR', 'Suriname', '2023-09-28 23:50:46'),
(208, 'SJ', 'Svalbard and Jan Mayen Islands', '2023-09-28 23:50:46'),
(209, 'SZ', 'Swaziland', '2023-09-28 23:50:46'),
(210, 'SE', 'Sweden', '2023-09-28 23:50:46'),
(211, 'CH', 'Switzerland', '2023-09-28 23:50:46'),
(212, 'SY', 'Syrian Arab Republic', '2023-09-28 23:50:46'),
(213, 'TW', 'Taiwan', '2023-09-28 23:50:46'),
(214, 'TJ', 'Tajikistan', '2023-09-28 23:50:46'),
(215, 'TZ', 'Tanzania, United Republic of', '2023-09-28 23:50:46'),
(216, 'TH', 'Thailand', '2023-09-28 23:50:46'),
(217, 'TG', 'Togo', '2023-09-28 23:50:46'),
(218, 'TK', 'Tokelau', '2023-09-28 23:50:46'),
(219, 'TO', 'Tonga', '2023-09-28 23:50:46'),
(220, 'TT', 'Trinidad and Tobago', '2023-09-28 23:50:46'),
(221, 'TN', 'Tunisia', '2023-09-28 23:50:46'),
(222, 'TR', 'Turkey', '2023-09-28 23:50:46'),
(223, 'TM', 'Turkmenistan', '2023-09-28 23:50:46'),
(224, 'TC', 'Turks and Caicos Islands', '2023-09-28 23:50:46'),
(225, 'TV', 'Tuvalu', '2023-09-28 23:50:46'),
(226, 'UG', 'Uganda', '2023-09-28 23:50:46'),
(227, 'UA', 'Ukraine', '2023-09-28 23:50:46'),
(228, 'AE', 'United Arab Emirates', '2023-09-28 23:50:46'),
(229, 'GB', 'United Kingdom', '2023-09-28 23:50:46'),
(230, 'US', 'United States', '2023-09-28 23:50:46'),
(231, 'UM', 'United States minor outlying islands', '2023-09-28 23:50:46'),
(232, 'UY', 'Uruguay', '2023-09-28 23:50:46'),
(233, 'UZ', 'Uzbekistan', '2023-09-28 23:50:46'),
(234, 'VU', 'Vanuatu', '2023-09-28 23:50:46'),
(235, 'VA', 'Vatican City State', '2023-09-28 23:50:46'),
(236, 'VE', 'Venezuela', '2023-09-28 23:50:46'),
(237, 'VN', 'Vietnam', '2023-09-28 23:50:46'),
(238, 'VG', 'Virgin Islands (British)', '2023-09-28 23:50:46'),
(239, 'VI', 'Virgin Islands (U.S.)', '2023-09-28 23:50:46'),
(240, 'WF', 'Wallis and Futuna Islands', '2023-09-28 23:50:46'),
(241, 'EH', 'Western Sahara', '2023-09-28 23:50:46'),
(242, 'YE', 'Yemen', '2023-09-28 23:50:46'),
(243, 'ZR', 'Zaire', '2023-09-28 23:50:46'),
(244, 'ZM', 'Zambia', '2023-09-28 23:50:46'),
(245, 'ZW', 'Zimbabwe', '2023-09-28 23:50:46');


ALTER TABLE `sql_paises`
ADD PRIMARY KEY (`id`);


ALTER TABLE `sql_paises`
MODIFY `id` int(11) NOT NULL AUTO_INCREMENT, AUTO_INCREMENT=246;

Conexión con MySQL

Para que nuestro filtro y/o buscador funcione correctamente necesitamos de una base de datos y un lenguaje que interactúe como mediador y conexión con MySQL. Por lo tanto, usaremos un archivo llamado db.php

<?php
// Conexion método PDO::setAttribute
try {
$dsn = "mysql:host=localhost;dbname=select5";
$dbh = new PDO($dsn, "root", "");
$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch (PDOException $e){
echo $e->getMessage();
}

?>

Buscador de etiqueta SELECT con Vanilla JavaScript

  • Usaremos el fichero llamado index.php en donde contendrá la interfaz gráfica del script
    Para la conexión con MySQL debemos de incluir el fichero db.php que contiene los parámetros de conexión de MySQL usando PDO para una mejor seguridad.
  • En este archivo, debemos incluir el enlace de la biblioteca Bootstrap 5 para una interfaz gráfica profesional y el enlace de la biblioteca dselect en el encabezado de esta página web.
  • Luego, tenemos que crear un cuadro de selección HTML y para llenar este cuadro de selección con datos dinámicos, aquí tenemos que escribir un script PHP para recuperar datos de la tabla sql_paises y llenar este cuadro de selección con datos dinámicos.
  • Por último, debemos de inicializar la biblioteca dselect, por lo que al usar el método dselect() inicializará la biblioteca dselect y para agregar el filtro de búsqueda, tenemos que agregar una opción de búsqueda con valor verdadero. Por lo tanto, después de agregar esta biblioteca se creará el Select Dropdown con Caja de búsqueda.
<?php
include_once("db.php");

$sql = "
SELECT pais_nombre FROM sql_paises
ORDER BY pais_nombre ASC
";

$resultados = $dbh->query($sql);

?>

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">

<!-- Bootstrap CSS -->
<link href="library/bootstrap-5/bootstrap.min.css" rel="stylesheet" />
<script src="library/bootstrap-5/bootstrap.bundle.min.js"></script>
<script src="library/dselect.js"></script>
<title>Bootstrap 5 Select Dropdown usando JavaScript con PHP</title>
<style>
.dropdown-menu {
width: 100%;padding: 0rem 0;
}
</style>
</head>
<body>
<div class="container mt-4">
<div class="card">
<div class="card-header"> Bootstrap 5 Select Dropdown usando JavaScript con PHP </div>
<div class="card-body">
<div class="row">
<div class="col-md-3"> </div>
<div class="col-md-6">
<select name="seleccion_box" class="form-select" id="seleccion_box">
<option value="">Seleccione Pais</option>
<?php
foreach($resultados as $row)
{
echo '<option value="'.$row["pais_nombre"].'">'.$row["pais_nombre"].'</option>';
}
?>
</select>
</div>
<div class="col-md-3"> </div>
</div>
</div>
</div>
</div>
</body>
</html>
<script>

var select_box_element = document.querySelector('#seleccion_box');

dselect(select_box_element, {
search: true
});

</script>

Librería script dselect.js

Este script contiene funciones elementales para inicializar las clases de BootStrap 5 para mostrar a lista desplegable donde el usuario final podrá realizar el filtro y/o búsqueda de elementos de una etiqueta SELECT de HTML 5.

function dselectUpdate(button, classElement, classToggler) {
const value = button.dataset.dselectValue
const target = button.closest(`.${classElement}`).previousElementSibling
const toggler = target.nextElementSibling.getElementsByClassName(classToggler)[0]
const input = target.nextElementSibling.querySelector('input')
if (target.multiple) {
Array.from(target.options).filter(option => option.value === value)[0].selected = true
} else {
target.value = value
}
if (target.multiple) {
toggler.click()
}
target.dispatchEvent(new Event('change'))
toggler.focus()
if (input) {
input.value = ''
}
}
function dselectRemoveTag(button, classElement, classToggler) {
const value = button.parentNode.dataset.dselectValue
const target = button.closest(`.${classElement}`).previousElementSibling
const toggler = target.nextElementSibling.getElementsByClassName(classToggler)[0]
const input = target.nextElementSibling.querySelector('input')
Array.from(target.options).filter(option => option.value === value)[0].selected = false
target.dispatchEvent(new Event('change'))
toggler.click()
if (input) {
input.value = ''
}
}
function dselectSearch(event, input, classElement, classToggler, creatable) {
const filterValue = input.value.toLowerCase().trim()
const itemsContainer = input.nextElementSibling
const headers = itemsContainer.querySelectorAll('.dropdown-header')
const items = itemsContainer.querySelectorAll('.dropdown-item')
const noResults = itemsContainer.nextElementSibling

headers.forEach(i => i.classList.add('d-none'))

for (const item of items) {
const filterText = item.textContent

if (filterText.toLowerCase().indexOf(filterValue) > -1) {
item.classList.remove('d-none')
let header = item
while(header = header.previousElementSibling) {
if (header.classList.contains('dropdown-header')) {
header.classList.remove('d-none')
break
}
}
} else {
item.classList.add('d-none')
}
}
const found = Array.from(items).filter(i => !i.classList.contains('d-none') && !i.hasAttribute('hidden'))
if (found.length < 1) {
noResults.classList.remove('d-none')
itemsContainer.classList.add('d-none')
if (creatable) {
noResults.innerHTML = `Press Enter to add "<strong>${input.value}</strong>"`
if (event.key === 'Enter') {
const target = input.closest(`.${classElement}`).previousElementSibling
const toggler = target.nextElementSibling.getElementsByClassName(classToggler)[0]
target.insertAdjacentHTML('afterbegin', `<option value="${input.value}" selected>${input.value}</option>`)
target.dispatchEvent(new Event('change'))
input.value = ''
input.dispatchEvent(new Event('keyup'))
toggler.click()
toggler.focus()
}
}
} else {
noResults.classList.add('d-none')
itemsContainer.classList.remove('d-none')
}
}
function dselectClear(button, classElement) {
const target = button.closest(`.${classElement}`).previousElementSibling
Array.from(target.options).forEach(option => option.selected = false)
target.dispatchEvent(new Event('change'))
}
function dselect(el, option = {}) {
el.style.display = 'none'
const classElement = 'dselect-wrapper'
const classNoResults = 'dselect-no-results'
const classTag = 'dselect-tag'
const classTagRemove = 'dselect-tag-remove'
const classPlaceholder = 'dselect-placeholder'
const classClearBtn = 'dselect-clear'
const classTogglerClearable = 'dselect-clearable'
const defaultSearch = false
const defaultCreatable = false
const defaultClearable = false
const defaultMaxHeight = '360px'
const defaultSize = ''
const search = attrBool('search') || option.search || defaultSearch
const creatable = attrBool('creatable') || option.creatable || defaultCreatable
const clearable = attrBool('clearable') || option.clearable || defaultClearable
const maxHeight = el.dataset.dselectMaxHeight || option.maxHeight || defaultMaxHeight
let size = el.dataset.dselectSize || option.size || defaultSize
size = size !== '' ? ` form-select-${size}` : ''
const classToggler = `form-select${size}`

const searchInput = search ? `<input onkeydown="return event.key !== 'Enter'" onkeyup="dselectSearch(event, this, '${classElement}', '${classToggler}', ${creatable})" type="text" class="form-control" placeholder="Buscar" autofocus>` : ''

function attrBool(attr) {
const attribute = `data-dselect-${attr}`
if (!el.hasAttribute(attribute)) return null

const value = el.getAttribute(attribute)
return value.toLowerCase() === 'true'
}

function removePrev() {
if (el.nextElementSibling && el.nextElementSibling.classList && el.nextElementSibling.classList.contains(classElement)) {
el.nextElementSibling.remove()
}
}

function isPlaceholder(option) {
return option.getAttribute('value') === ''
}

function selectedTag(options, multiple) {
if (multiple) {
const selectedOptions = Array.from(options).filter(option => option.selected && !isPlaceholder(option))
const placeholderOption = Array.from(options).filter(option => isPlaceholder(option))
let tag = []
if (selectedOptions.length === 0) {
const text = placeholderOption.length ? placeholderOption[0].textContent : ' '
tag.push(`<span class="${classPlaceholder}">${text}</span>`)
} else {
for (const option of selectedOptions) {
tag.push(`
<div class="${classTag}" data-dselect-value="${option.value}">
${option.text}
<svg onclick="dselectRemoveTag(this, '${classElement}', '${classToggler}')" class="${classTagRemove}" width="14" height="14" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="currentColor"><path d="M0 0h24v24H0z" fill="none"/><path d="M12 2C6.47 2 2 6.47 2 12s4.47 10 10 10 10-4.47 10-10S17.53 2 12 2zm5 13.59L15.59 17 12 13.41 8.41 17 7 15.59 10.59 12 7 8.41 8.41 7 12 10.59 15.59 7 17 8.41 13.41 12 17 15.59z"/></svg>
</div>
`)
}
}
return tag.join('')
} else {
const selectedOption = options[options.selectedIndex]
return isPlaceholder(selectedOption)
? `<span class="${classPlaceholder}">${selectedOption.innerHTML}</span>`
: selectedOption.innerHTML
}
}

function selectedText(options) {
const selectedOption = options[options.selectedIndex]
return isPlaceholder(selectedOption) ? '' : selectedOption.textContent
}

function itemTags(options) {
let items = []
for (const option of options) {
if (option.tagName === 'OPTGROUP') {
items.push(`<h6 class="dropdown-header">${option.getAttribute('label')}</h6>`)
} else {
const hidden = isPlaceholder(option) ? ' hidden' : ''
const active = option.selected ? ' active' : ''
const disabled = el.multiple && option.selected ? ' disabled' : ''
const value = option.value
const text = option.textContent
items.push(`<button${hidden} class="dropdown-item${active}" data-dselect-value="${value}" type="button" onclick="dselectUpdate(this, '${classElement}', '${classToggler}')"${disabled}>${text}</button>`)
}
}
items = items.join('')
return items
}

function createDom() {
const autoclose = el.multiple ? ' data-bs-auto-close="outside"' : ''
const additionalClass = Array.from(el.classList).filter(className => {
return className !== 'form-select'
&& className !== 'form-select-sm'
&& className !== 'form-select-lg'
}).join(' ')
const clearBtn = clearable && !el.multiple ? `
<button type="button" class="btn ${classClearBtn}" title="Clear selection" onclick="dselectClear(this, '${classElement}')">
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 14 14" fill="none">
<path d="M13 1L0.999999 13" stroke-width="2" stroke="currentColor"></path>
<path d="M1 1L13 13" stroke-width="2" stroke="currentColor"></path>
</svg>
</button>
` : ''
const template = `
<div class="dropdown ${classElement} ${additionalClass}">
<button class="${classToggler} ${!el.multiple && clearable ? classTogglerClearable : ''}" data-dselect-text="${!el.multiple && selectedText(el.options)}" type="button" data-bs-toggle="dropdown" aria-expanded="false"${autoclose}>
${selectedTag(el.options, el.multiple)}
</button>
<div class="dropdown-menu">
<div class="d-flex flex-column">
${searchInput}
<div class="dselect-items" style="max-height:${maxHeight};overflow:auto">
${itemTags(el.querySelectorAll('*'))}
</div>
<div class="${classNoResults} d-none">No results found</div>
</div>
</div>
${clearBtn}
</div>
`
removePrev()
el.insertAdjacentHTML('afterend', template) // insert template after element
}
createDom()

function updateDom() {
const dropdown = el.nextElementSibling
const toggler = dropdown.getElementsByClassName(classToggler)[0]
const dSelectItems = dropdown.getElementsByClassName('dselect-items')[0]
toggler.innerHTML = selectedTag(el.options, el.multiple)
dSelectItems.innerHTML = itemTags(el.querySelectorAll('*'))
if (!el.multiple) {
toggler.dataset.dselectText = selectedText(el.options)
}
}

el.addEventListener('change', updateDom)
}

Conclusiones de buscador en select con Vanilla JavaScript

Si ha seguido todos los pasos anteriores, puede agregar el filtro del cuadro de búsqueda en el cuadro desplegable a cliquear la etiqueta SELECT usando JavaScript con PHP y la base de datos MySQL.

A continuación, puede encontrar el enlace del código fuente y la demostración en línea de este tutorial.

Ver Demostración

Nestor Tapia

Bloggero, amante de la programación PHP, innovador y me fascina compartir información. Desde que conocí el entorno informatico y el internet me llamó la atención la programación, Por tal motivo he creado mi blog BAULPHP.COM para compartir mis experiencias con todos ustedes. ¡Gracias por leerme!.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

Botón volver arriba