Habíamos mencionado en otro tutorial como comenzar el desarrollo con Grocerycrud para Codeigniter PHP, a continuación veremos como hacer que varios combo box o dropdown están relacionados entre si y dependen uno de otro.
Veamos un ejemplo completo con una Base de datos denominada Inmobiliaria, la estructura será la siguiente:
Estructura de tabla para la tabla `inmuebles`
CREATE TABLE IF NOT EXISTS `inmuebles` ( `idinmueble` int(11) NOT NULL, `idusuario` int(11) DEFAULT NULL, `fechaAlta` date DEFAULT '0000-00-00', `idtipoimueble` int(6) DEFAULT '0', `precio` decimal(10,2) DEFAULT '0.00', `descripcion` text, `idprovincia` int(10) DEFAULT NULL, `idlocalidad` int(10) DEFAULT NULL, `direccion` varchar(150) DEFAULT NULL, `foto` varchar(255) DEFAULT NULL, `disponible` enum('Si','No') DEFAULT NULL ) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `localidades` ( `idlocalidad` int(11) NOT NULL, `localidad` varchar(200) DEFAULT NULL, `idprovincia` int(11) DEFAULT '0' ) ENGINE=MyISAM AUTO_INCREMENT=3604 DEFAULT CHARSET=utf8; CREATE TABLE IF NOT EXISTS `usuarios` ( `idusuario` int(11) NOT NULL, `nombre` varchar(150) NOT NULL DEFAULT '' ) ENGINE=MyISAM AUTO_INCREMENT=161 DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `tipoinmueble` ( `idtipoinmueble` int(6) NOT NULL, `tipoinmueble` varchar(150) NOT NULL DEFAULT '' ) ENGINE=MyISAM AUTO_INCREMENT=15 DEFAULT CHARSET=latin1; CREATE TABLE IF NOT EXISTS `provincias` ( `idprovincia` int(11) NOT NULL, `provincia` varchar(255) COLLATE latin1_spanish_ci DEFAULT NULL ) ENGINE=MyISAM AUTO_INCREMENT=32 DEFAULT CHARSET=latin1 COLLATE=latin1_spanish_ci;Podemos realizar mediante phpmyadmin un diagrama de relaciones que será el siguiente:
En el tutorial anterior vimos como instalar y configurar Grocerycrud, aquÍ crearemos la aplicación, creamos el controlador Inmo.php
<?php defined('BASEPATH') OR exit('No direct script access allowed'); class Inmo extends CI_Controller { function __construct() { parent::__construct(); $this->load->database(); $this->load->helper('url'); $this->load->model('grocery_crud_model'); $this->load->library('Grocery_CRUD'); } public function index() { $crud = new grocery_CRUD(); $crud->set_theme('flexigrid'); $crud->set_table('inmuebles'); $output = $crud->render(); $this->load->view('inmolista', $output); } } ?>A continuación creamos la vista que llamaremos listainmo.php, los archivos CSS y JQuery los tomará de la configuración de Grocery Crud por ello aquí solo los listamos:
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <?php foreach($css_files as $file): ?> <link type="text/css" rel="stylesheet" href="<?php echo $file; ?>" /> <?php endforeach; ?> <?php foreach($js_files as $file): ?> <script src="<?php echo $file; ?>"></script> <?php endforeach; ?> <body> <div style='height:20px;'></div> <div> <?php echo $output; ?> </div> </body> </html>El resultado al ejecutar la web en un navegador http://localhost/pro...os/inmobi/Inmo/
Podemos observar que los id muestran números en lugar de datos esto es porque las tablas no están relacionadas para relacionarlas haremos los siguiente, en el controlador debajo de set_table indicaremos.
$crud->set_relation(‘idarelacionar’,’tablaarelacionar’,’campoamostrar’);De ejemplo quiero mostrar el nombre de usuario de la tabla usuario, con el id de usuario de la tabla inmuebles entonces deberé escribir el siguiente código:
$crud->set_relation('idusuario','usuarios','nombre');Como resultado de ejecutar veremos que en lugar un numero en idusuario nos muestra el nombre.
A continuación vamos a relacionar los ademas campos, provincia y localidades.
$crud->set_relation('idtipoinmueble','tipoinmueble','tipoinmueble'); $crud->set_relation('idprovincia','provincias','provincia'); $crud->set_relation('idlocalidad','localidades','localidad');Después de ejecutar veremos los id con su respectiva relación:
En el caso de imágenes deberemos usar
$crud->set_field_upload(campo,'rutadeimagen');Entonces utilizaremos el mismo directorio de Grocery crud para guardar imágenes
$crud->set_field_upload('foto','assets/uploads/files');Aunque podemos mostrar en el listado los campos y combos relacionados, no son dependientes, queremos que al seleccionar una provincia en el combo de provincias se active en forma automática el de localidades y se llene con las localidades de esa provincia, ademas queremos que esa relación se mantenga cuando añadimos un inmueble o cuando lo editamos.
Para hacer los combos dependientes utilizaremos una función callback. Un callback o devolución de llamada es una alternativa al polimorfismo, esto fue un tema que tratamos en otro tutorial para saber implementar las clases:
Clases y Polimorfismo con PHP
Donde a una función se le asigna como parámetro otra función, una función de nivel inferior. Un callback puede actuar cuando se añade un registro o cuando se modifica. Este método permite una gran reutilización de código.
La sentencia de un callback puede ser la siguiente en el controlador.
$crud->callback_add_field(‘nombrecallback’, Array(parametros));En este caso el callback sera idlocalidad y la función sera cbklocalidades
$crud->callback_add_field('idlocalidad', array($this, 'cbklocalidades')); $crud->callback_edit_field('idlocalidad', array($this, 'cbklocalidades'));A continuación creamos la funcion cbklocalidades que sera nuestro callback invocado cuando agregemos o editemos un registro.
//Callback que genera el combo idlocalidades function cbklocalidades() { //creamos el combo $combo = '<select name="idlocalidad" class="chosen-select" data-placeholder="Seleccionar localidad" style="width: 300px; display: none;">'; $fincombo = '</select>'; //Tomamos el id de inmueble si se enviocomo parámetro por url $idinmuebleurl = $this->uri->segment(4); //Verificamos la operacion que estamos haciendo si agregamos o editamos $crud = new grocery_CRUD(); $estado = $crud->getState(); //Si estamos editando y el id de inmueble no es vació if(isset($idinmuebleurl) && $estado == "edit") { //consultamos la provincia y la localidad actual del inmueble $this->db->select('idprovincia, idlocalidad') ->from('inmuebles') ->where('idinmueble', $idinmuebleurl); $db = $this->db->get(); $row = $db->row(0); $idprovincia = $row->idprovincia; $idlocalidad = $row->idlocalidad; //Cargamos el combo con todas las localidades de la pronvincia $this->db->select('*') ->from('localidades') ->where('idprovincia', $idprovincia); $db = $this->db->get(); //Si ecnontramos el id de localidad actual lo ponemos como selecionado //sino seguimos cargando las demas localidades foreach($db->result() as $row): if($row->idlocalidad == $idlocalidad) { $combo .= '<option value="'.$row->idlocalidad.'" selected="selected">'.$row->localidad.'</option>'; } else { $combo .= '<option value="'.$row->idlocalidad.'">'.$row->localidad.'</option>'; } endforeach; //Devolvemos el combo cargado return $combo.$fincombo; } else { return $combo.$fincombo; } }A continuación deberemos crear la función buscarlocalidades que es la que indicamos como función de consulta dentro del Callback:
//Consulta de localidades function buscarlocalidades() { //Tomo el id de provincia que se envió como parámetro por url al seleccionar //una provincia del combo idprovincia $idprovincia = $this->uri->segment(3); //consulto las localidades segun la provincia seleccionada $this->db->select("*") ->from('localidades') ->where('idprovincia', $idprovincia); $db = $this->db->get(); //Asigno la respuesta sql a un array $array = array(); foreach($db->result() as $row): $array[] = array("value" => $row->idlocalidad, "property" => $row->localidad); endforeach; echo json_encode($array); exit; }A continuación deberemos crear la vista que procese los combos y añada las sentencias jquery en forma dinámica para ello crearemos en la carpeta view un archivo denominado combos_dependientes.php.
<? //Verificamos la operacion o estado de Grocery crud if(isset($estado) && ($estado == 'add' || $estado == 'edit')) { //Generamos el script Jquery que controlara los combos dinamicamente echo '<script type="text/javascript">'; echo '$(document).ready(function() {'; for($i = 0; $i <= sizeof($combos)-1; $i++): //tomamos las variavles que asignamos en $datos del controlador echo 'var '.$combos[$i].' = $('select[name="'.$combos[$i].'"]');'; /asignamos el icono if($i != sizeof($combos)-1) { echo '$('#'.$combos[$i].'_input_box').append('<img src="'.$icon_ajax.'" border="0" id="'.$combos[$i].'_ajax_loader" class="dd_ajax_loader" style="display: none;">');'; } if($i > 0 && $estado == 'add') { //Si estamos añadiendo un nuevo registro //Ocultamos los combos de jerarquía inferior echo '$('#'.$combos[$i].'_input_box').hide(); echo $combos[$i].'.children().remove().end();'; } endfor; for($i = 1; $i <= sizeof($combos)-1; $i++): /Añadimos los datos a los combos de jerarquia inferior echo $combos[$i-1].'.change(function() {'; echo 'var select_value = this.value;'; echo '$('#'.$combos[$i-1].'_ajax_loader').show();'; //Borramos todos los datos anteriores echo $combos[$i].'.find('option').remove();'; echo 'var myOptions = "";'; //Asignamos el nuevo llistado que traemos de buscarlocalidades() echo '$.getJSON(''.$url[$i].''+select_value, function(data) {'; //listamos los datos echo $combos[$i].'.append('<option value=""></option>');'; echo '$.each(data, function(key, val) {'; echo $combos[$i].'.append('; echo '$('<option></option>').val(val.value).html(val.property)'; echo ');'; echo '});'; echo '$('#'.$combos[$i].'_input_box').show();'; for($x = $i+1; $x <= sizeof($combos)-1; $x++): echo '$('#'.$combos[$x].'_input_box').hide();'; endfor; echo $combos[$i-1].'.each(function(){'; echo '$(this).trigger("liszt:updated");'; echo '});'; echo $combos[$i].'.each(function(){'; echo '$(this).trigger("liszt:updated");'; echo '});'; echo '$('#'.$combos[$i-1].'_ajax_loader').hide();'; echo '});'; echo '});'; endfor; echo '});'; echo '</script>'; } ?>Para finalizar vamos a la vista y añadimos el siguiente código que relaciones la vista con el archivo combos_dependientes.php
<?php if(isset($combo_setup)) { $this->load->view('combos_dependientes', $combo_setup); } ?>
Luego si ejecutamos podremos ver tanto cuando añadimos un nuevo inmueble o cuando editamos como los combos provincia y localidades han quedado relacionados y localidades, depende de provincia.
Si quisiéramos hacer varios combos dependientes deberemos hacer un callback para cada par de combos.
Supongamos que tenemos paises, provincias y localidades y queremos hace dependiente países con provincia y provincias con ciudades, entonces deberemos crear un callback para cada dependencias por ejemplo:
$crud->callback_add_field(idprovincia, array($this, 'cbkprovincia')); $crud->callback_edit_field('idprovincia', array($this, 'cbkprovincia')); $crud->callback_add_field('idlocalidad', array($this, 'cbklocalidades')); $crud->callback_edit_field('idlocalidad', array($this, 'cbklocalidades'));Para el combo países no se crea un callback ya que al ser el primero en jerarquía no tiene dependencia de otro combo.
hola buenas ttardes. gusto en saludarlos. bueno la verdad es que la ultima parte no funciona. hay un error de sintaxis en la parte correspondiente a view en lo de combos_dependientes.php. SI ME HACE ESE INMENSO FAVOR ESTARE ETERNAMENTE AGRADECIDO.. SOLO ME FALTA ARREGLAR ESE ERROR DE SINTAXIS QUE NO LO HE ENCONTRADO POR NINGUN LADO. el resto ya lo tengo corriendo.. agradecimientos si alguien me puede colaborar en esta parte
.