Con este tutorial vamos a aprender como implementar select anidado o select dependientes usando KumbiaPHP y jquery. Es una lista simple enlazada con tres niveles: Regiones, comunas y ciudades.
Implementando el select anidado
Primero que todo cargamos la librería jquery añadiendo en nuestro template activo la siguiente línea:
<?= Tag::js('jquery/jquery.min'); ?>
La base de datos
CREATE TABLE `ciudad` (
`id` int(4) NOT NULL AUTO_INCREMENT,
`comuna_id` int(4) NOT NULL,
`nombre` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_ciudad__comuna` (`comuna_id`),
CONSTRAINT `FK_ciudad__comuna` FOREIGN KEY (`comuna_id`) REFERENCES `comuna` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO `ciudad` VALUES (1,1,'Primera Ciudad'),(2,2,'Primera Ciudad'),(3,2,'Segunda Ciudad'),(4,3,'Primera Ciudad'),(5,3,'Segunda Ciudad'),(6,3,'Tercera Ciudad');
CREATE TABLE `comuna` (
`id` int(4) NOT NULL AUTO_INCREMENT,
`region_id` int(4) NOT NULL,
`nombre` varchar(100) NOT NULL,
PRIMARY KEY (`id`),
KEY `FK_comuna__region` (`region_id`),
CONSTRAINT `FK_comuna__region` FOREIGN KEY (`region_id`) REFERENCES `region` (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO `comuna` VALUES (1,1,'Primera Comuna'),(2,1,'Segunda Comuna'),(3,2,'Primera Comuna'),(4,3,'Primera Comuna');
CREATE TABLE `region` (
`id` int(4) NOT NULL AUTO_INCREMENT,
`nombre` varchar(100) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
INSERT INTO `region` VALUES (1,'Primera Region'),(2,'Segunda Region'),(3,'Tercera Region');
Los modelos
Vamos a tener tres modelos que se encargaran de la consulta de los datos, heredando como no de la clase ActiveRecord:
Archivo: app/models/region.php
<?php
class Region extends ActiveRecord
{
/**
* Lista todas las regiones
* @return array
*/
public function all()
{
return $this->find('order: nombre');
}
}
Archivo: app/models/comuna.php
<?php
class Comuna extends ActiveRecord
{
/**
* Lista todas las comunas de una región
*
* @param int $region_id
* @return array
*/
public function allByRegion(int $region_id)//validación int de PHP7
{
return $this->find("region_id = $region_id", 'order: nombre');
}
}
Archivo: app/models/ciudad.php
<?php
class Ciudad extends ActiveRecord
{
/**
* Lista todas las ciudades de una comuna
*
* @param int $region_id
* @return array
*/
public function allByComuna(int $comuna_id)//validación int de PHP7
{
return $this->find("comuna_id = $comuna_id", 'order: nombre');
}
}
El controlador
Usaremos de ejemplo el controlador UserController aunque no implementaremos la funcionalidad de creación de un usuario para enforcarnos en el select anidado. Tendrá dos funciones auxiliares que nos cargarán los respectivos selects sin template, getComunas() y getCiudades().
Archivo: app/controllers/user_controller.php
<?php
/**
* Controlador para las acciones y vistas con el usuario
*/
class UserController extends AppController
{
public function index()
{
}
public function create()
{
//se verifica si se ha enviado via POST los datos
if (Input::hasPost('user')) {
//
}
}
public function getComunas()
{
//No es necesario el template
View::template(null);
//Carga la variable $region_id en la vista
$this->region_id = Input::post('region_id');
}
public function getCiudades()
{
//No es necesario el template
View::template(null);
//Carga la variable $comuna_id en la vista
$this->comuna_id = Input::post('comuna_id');
}
}
Las vistas
La primera vista es la de crear un usuario, la cual contendrá los tres selects, aunque en principio solo mostrará el primero y unas capas vacias, ya que los siguientes dependen de qué se seleccione y serán cargados mediante ajax:
Archivo: app/views/user/create.phtml
<h1>Crear usuario</h1>
<?= Html::linkAction('', 'Listar usuarios', 'class="button"') ?>
<?php View::content() ?>
<?= Form::open() ?>
<div class="row">
<div class="six columns">
<label for="user_region_id">Región</label>
<?= Form::dbSelect('user.region_id', 'nombre', array('region', 'all'), '- Seleccione -'); ?>
</div>
</div>
<div class="row">
<div class="six columns">
<label for="user_comuna_id">Comuna</label>
<div id='div_comunas'></div>
</div>
</div>
<div class="row">
<div class="six columns">
<label for="user_ciudad_id">Ciudad</label>
<div id='div_ciudades'></div>
</div>
</div>
<input class="button-primary" value="Enviar" type="submit">
<?= Form::close() ?>
<script type='text/javascript'>
$(document).on('change', "#user_region_id", function () {
var region_id = $('#user_region_id').val();
$.ajax({
type: "POST",
url: "<?php echo PUBLIC_PATH . 'user/getComunas/'; ?>",
data: "region_id=" + region_id,
success: function (html) {
$("#div_comunas").html(html);
}
});
});
</script>
La vista anterior con javascript añade un listener para que cuando el valor del select que contiene las regiones cambie, haga un llamado mediante ajax para obtener el listado de comunas por región y este resultado lo carga en la capa div_comunas.
La siguiente vista cargará el select usando el helper Form::dbSelect() usando el método allByRegion() del modelo Comuna y pasándole como parámetro $region_id.
Archivo: app/views/user/getComunas.phtml
<?= Form::dbSelect("user.comuna_id", 'nombre', array('comuna', 'allByRegion', $region_id), '- Seleccione -'); ?>
<script type='text/javascript'>
$(document).on('change', "#user_comuna_id", function () {
var comuna_id = $('#user_comuna_id').val();
$.ajax({
type: "POST",
url: "<?php echo PUBLIC_PATH . 'user/getCiudades/'; ?>",
data: "comuna_id=" + comuna_id,
success: function (html) {
$("#div_ciudades").html(html);
}
});
});
</script>
La vista anterior con javascript añade un listener para que cuando el valor del select que contiene las comunas cambie, haga un llamado mediante ajax para obtener el listado de ciudades por comuna y este resultado lo carga en la capa div_ciudades.
La siguiente vista es similar a getComunas.phtml, lo que hace es cargar todas las ciudades que pertenezcan a una comunidad usando el helper Form::dbSelect() pasandole como parámetros el nombre del modelo ciudad, el método allByComuna() y el parámetro de consulta $comuna_id.
Archivo: app/views/user/getCiudades.phtml
<?= Form::dbSelect("user.ciudad_id", 'nombre', array('ciudad', 'allByComuna', $comuna_id), '- Seleccione -'); ?>
Ejecutando el ejemplo
Cuando cargamos la url /user/create veremos algo como lo siguiente, en primera instacia solo va mostrar las regiones:
Lo siguientes dos select se mostraran comforme se vaya seleccionando una región y posteriormente una comuna.
Descargar código completo
Como siempre, el código completo está disponible para todos en el siguiente repositorio en Github listo para usar con Docker: https://github.com/henrystivens/dependent-select
gracias :v
Con mucho gusto. ¿Qué tal te pareció? ¿Te funciona el código?
Tienen un ejemplo sencillo de ajax. mostrar dos consultas diferentes en la misma vista. por ejemplo en la misma vista que exista dos botones….el primero que al presionarlo averigüe si existe un registro y con base a eso muestre un mensaje y el otro que al presionarlo me devuelva un array