- El modelo.
<?php
class MunicipioPeer extends BaseMunicipioPeer
{
static public function doSelectByEstado($estado)
{
$c= new Criteria();
$c->add(MunicipioPeer::ID_ESTADO ,$estado);
return MunicipioPeer::doSelect($c);
}
}
- El componente.
<?php
class municipioComponents extends sfComponents
{
public function executeSelectByEstado()
{
$this->municipios = MunicipioPeer::doSelectByEstado($this->id_estado);
}
}
El parcial _selectByEstado.php de el componente sería el siguiente:
<?php
echo select_tag($nombre,options_for_select(array(''=>'Seleccione')+
_get_options_from_objects($municipios),
isset($id_municipio)?$id_municipio:''),array());?>
En el parcial observamos las variables comentadas previamente ($nombre para el nombre del objeto select, $municipios, el arreglo de municipios que se generó previamente en la parte de la lógica de negocio del componente y $id_municipio, que es el valor seleccionado por defecto).
- Usando el componente en un modulo generado con admin generator.
generamos el modulo medio con el admin generator y en el generator.yml indicamos que queremos capturar en la pantalla de edición del medio el estado y municipio del medio.
edit:
title: REGISTRO DE MEDIOS
display: [nom_medio, id_estado, id_municipio .....]
Al ejecutar la acción edit del modulo medio veremos que se listan todos los municipios, sin filtro por estados. Lo primero que vamos a hacer es colocar que por defecto, cuando se ejecute la acción los municipios salgan filtrados. Para eso vamos a crear un parcial _id_municipio.php en el módulo de medios y en ese parcial llamamos al componente que creamos previamente.
<span id="municipio">
<?php include_component('municipio','selectByEstado',array(
'id_estado'=>$medio->getIdEstado(),
'nombre'=>'medio[id_municipio]',
'id_municipio'=>$medio->getIdMunicipio(),
));
?>
</span>
Tal vez surja la pregunta de por qué el select se colocó dentro de un span, pero más adelante aclararé dicha duda. Ahora vamos a proceder a establecer que la lista de municipio se actualice via Ajax cada vez que se seleccione un estado distinto. Para ello vamos a hacer un parcial llamado _id_estado.php para el select del estado y lo colocaremos un observador, que dispare una acción ajax cada vez que cambie el mismo:
<?php $value = object_select_tag($medio, 'getIdEstado', array (
'related_class' => 'Estado',
'control_name' => 'medio[id_estado]',
'include_custom' => 'Seleccione',
)); echo $value ? $value : ' ' ?>
<?php echo observe_field('medio_id_estado',array(
'update' => 'municipio',
'url' => 'municipio/listByEstado',
'with' => "'id_estado=' + value+'&nombre=medio[id_municipio]'",
)) ?>
Note que en el helper observe_field, se utiliza el id del objeto select, y no el nombre. El id lo puedes ubicar observando el código fuente de la página que genera la acción, o lo puedes deducir del nombre. Adicionalmente el helper observe_field hace una llamada asíncrona a una acción en particular, en nuestro ejemplo esa acción esta en el módulo municipio y se llama listByEstado. A esta acción se le pasarán 2 parámetros, que son el id del estado y el nombre del objeto a generar.
- Creando la acción del Ajax.
En actions.class.php.
<?php
class municipioActions extends autoMunicipioActions
{
public function executeListByEstado()
{
$this->municipios = MunicipioPeer::doSelectByEstado($this->getRequestParameter('id_estado'));
}
en la vista listByEstadoSuccess.php:
<?php use_helper('Object') ?>
<?php include_partial('selectByEstado',array(
'municipios'=>$municipios,
'nombre'=>$sf_request->getParameter('nombre'),
));
?>
Solo queda indicar en el generetor.yml de medio que utilize los 2 parciales que creamos.
edit:
title: REGISTRO DE MEDIOS
display: [nom_medio, _id_estado, _id_municipio .....]
A partir de ahora, cuando se ejecute el la acción edit del modulo medio, si estamos editando un registro nuevo, veremos la lista de municipios blanco la primera vez, y si es un registro existente, veremos la lista de municipios relacionadas con el id del estado del registro. En cualquiera de los casos, al seleccionar un nuevo estado, automáticamente se actualizará vía ajax el span municipio con una nueva lista de municipios, basados en el estado seleccionado.
- Algunas consideraciones.
- Por que actualizar un span y no actualizar el objeto select directamente?. Es posible hacerlo, solo bastaría con indicar al observer que el update lo haga directamente al objeto DOM medio_id_municipio, y en la vista de la acción Ajax usar solamente el helper options_for_select para que solo se genere el código html de las opciones. Esto funcionaría perfectamente en Firefox, pero no en internet explorer, ya que este navegador tiene un bug que hace que falle cualquier intento de actualizar un objeto select vía javascript con un innerHTML.
- Se puede hacer que la acción listbyEstado del módulo municipio solo se ejecute si se llama via Ajax colocandole una condicion if (!$this->getRequest()->isXmlHttpRequest()) en el ćodigo de la acción.
- Se le pueden colocar efectos a la llamada realizada por el observer_field (desvanecimiento, condiciones en caso de que la acción genere un error, entre otras).
- Y que pasa si tengo un subnivel adicional?.