Combos Anidados

Buenos dias, tengo varios dias intentando hacer unos combos dependientes y queria ver si me podian ayudar. pues aqui la cuestion.

Mis tablas son:


tbl_estado

id

estado


tbl_municipio

id

idestado

municipio


tbl_Parroquia

id

idmunicipio

parroquia


La tabla que necesito que tenga la ubicacion se llama tbl_estructura y en ella tengo almacenado solo el id de la parroquia, ya que con el se puede saber todo lo demas.


tbl_estructura

id

idparroquia

denominacion


Una vez sabiendo eso tengo mi Form para crear un nuevo organismo en el mismo tengo este codigo, hasta ahora solo he trabajado en la relacion Estado-Municipio que obviamente no he podido realizar. en el form tengo esto


<div class="row">

		<?php echo $form->labelEx($model,'idestado'); ?>

		<?php echo $form->dropDownList($model,'id', //idestado

		CHtml::listData(TblEstado::model()->findAll(),'id','estado'),

			array(

				'ajax'=>array(

					'type'=>'POST',

					'url'=>CController::createUrl('TblEstructura/Selectestado'),

					'update'=>'#'.CHtml::activeId($model,'municipio'),

					),

				)

			//CHtml::listData(TblEstado::model()->findAll(),'id','estado')

		); ?>

		<!-- <?php echo $form->error($model,'idestado'); ?>  No tienen Error porque no son necesario-->

	</div>

	

	

	<div class="row">

		<?php echo $form->labelEx($model,'municipio'); ?>

		<?php echo $form->dropDownList($model,'id',

			CHtml::listData(TblMunicipio::model()->findAll(),'id','municipio')

		); ?> 

	</div>

	<div class="row">

		<?php echo $form->labelEx($model,'idparroquia'); ?>

		<?php echo $form->dropDownList($model,'idparroquia',

			CHtml::listData(TblParroquia::model()->findAll(),'id','parroquia')

		); ?> 

		<?php echo $form->error($model,'idparroquia'); ?>

	</div>



en el modelo tengo la funcion Selectestado asi:


public function actionSelectestado() 

	{


		$id_uno = $_POST ['TblEstructura']['id'];

		$lista = TblMunicipio::model()->findAll('id = :id_uno',array(':id_uno'=>$id_uno));

		$lista = CHtml::listData($lista, 'id', 'municipio');


		foreach ($lista as $valor => $municipio) {

			echo CHtml::tag('option',array('value'=>$valor),CHtml::encode($municipio),true);

		}


	}

Todo lo hice siguiendo un tutorial bastante bueno de youtube.

cambie algunas cosas ya que la relacion que muestran en el video no igual a la mia. la cuestion esta en que no me actualiza el combo de municipio. obviamente estoy haciendo algo mal, pero no se que es… agradeceria cualquier ayuda.

mmmm no se si estoy mal pero creo q a tus tablas les falta un campo que la relacione con la anterior

tbl_estado

id

estado


tbl_municipio

id

municipio

idestado


tbl_Parroquia

id

parroquia

idmunicipio

otra cosa el post que te llega debe ser el id del estado "idestado"




public function actionSelectestado() 

        {


                $id_uno = $_POST ['TblEstructura']['idestado'];

                $lista = TblMunicipio::model()->findAll('id = :id_uno',array(':id_uno'=>$id_uno));

                $lista = CHtml::listData($lista, 'id', 'municipio');


                foreach ($lista as $valor => $municipio) {

                        echo CHtml::tag('option',array('value'=>$valor),CHtml::encode($municipio),true);

                }


        }



PD: creo que tu codigo tiene mas errores :D pero ps corrige lo q te pase y hay vamos viendo q mas sale xD

Gracias erick. Ya coloque los campos de relación entre las tablas.

Despues de cambiar lo que me dijiste vino un error. lo que muestra el firebug es este error


<h1>PHP Error [8]</h1>

<p>Undefined index: idestado (/var/www/yii/directorioWeb/protected/controllers/TblEstructuraController.php:180)</p>

<pre>#0 /var/www/yii/directorioWeb/protected/controllers/TblEstructuraController.php(180): CWebApplication->handleError()

#1 /var/www/yii/framework/web/actions/CInlineAction.php(49): TblEstructuraController->actionSelectestado()...

Por otra parte tambien tengo un problema en el _form cuando llamo el $model, ‘id’ DropdownList


<?php echo $form->dropDownList($model,'id',

tanto a estado como a municipio los llamo igual. no se si sera ese el problema porque inspeccionando con el firebug los "name" son los mismos


<div class="row">

<label for="TblEstructura_idestado">Idestado</label>

<select id="TblEstructura_id" name="TblEstructura[id]">

</div>

<div class="row">

<label for="TblEstructura_municipio">Municipio</label>

<select id="TblEstructura_id" name="TblEstructura[id]">

</div>

Tus tablas deben quedas asi:

"te subrayo en colores para que veas la relacion"

tbl_estado

[color="#FF0000"]id_estado[/color]

estado


tbl_municipio

[color="#0000FF"]id_municipio[/color]

[color="#FF0000"]id_estado[/color]

municipio


tbl_Parroquia

[color="#FF8C00"]id_parroquia[/color]

[color="#0000FF"]id_municipio[/color]

parroquia

En tu Form vas a poner algo asi




<div class="row">

<?php echo $form->labelEx($model,'id_estado'); ?>


 <?php 

              echo $form->dropDownList($model,'id_estado',CHtml::listData(TblEstado::model()->findAll(),'id_estado','estado'),

                        array(

                            'ajax' => array(

                            'type' => 'POST',

                            'url' => CController::createUrl('TblEstructura/Selecmunicipio'),

                            'update' => '#'.CHtml::activeId($model,'id_municipio'), /* deberias cambiar tus id y renombrarlos decuardo a tu tabla ejem: tabla municipios seria id_municipio, tabla estado seria id_estado de tal manera que no te saque errore por poner el mismo nombre a un campo*/

                        ),'prompt' => 'Seleccione un Estado...'

                  )

              );

        ?>


 </div>


<div class="row">

  <?php echo $form->labelEx($model,'id_municipio'); ?>

 


    <?php 

              echo $form->dropDownList($model,'id_municipio',array(),

                        array(

                            'ajax' => array(

                            'type' => 'POST',

                            'url' => CController::createUrl('TblEstructura/SelecParroquia'),

                            'update' => '#'.CHtml::activeId($model,'id_parroquia'),

                        ),

                  )

              );

        ?>        

 </div>


<div class="row">

    <?php echo $form->labelEx($model,'id_parroquia'); ?>


    <?php echo $form->dropDownList($model,'id_parroquia',array()); ?>


</div>

        



Y en tu controlador vas a agregar lo siguinte:




<?php 


public function actionSelecmunicipio()

    {

    $id= $_POST['TblEstructura']['id_estado']; 

   

     $data = TblMunicipio::model()->findAll('id_estado=:id',array(':id' => $id));


             $data = CHtml::listData($data,'id_municipio', 'municipio');

    echo CHtml::tag('option',array('value' => ''),'Seleccione un Municipio...',true);

            foreach($data as $id1 => $value)

            {

                echo CHtml::tag('option',array('value' => $id1),CHtml::encode($value),true);

            }


    }  


//en caso de que la parroquia sea dependiente de los municipios


    public function actionSelecParroquia()

    {

    $id= $_POST['TblEstructura']['id_municipio']; 

    


     $data = TblParroquia::model()->findAll('id_municipio=:id',array(':id' => $id-1));


             $data = CHtml::listData($data,'id_parroquia','parroquia');

    echo CHtml::tag('option',array('value' => 0),'Seleccione la parroquia...',true);

            foreach($data as $id1 => $value)

            {

                echo CHtml::tag('option',array('value' => $id1),CHtml::encode($value),true);

            }


    }  

?>




Recuerda dar los permisos correspondientes a las Acciones SelecParroquia y Selecmunicipio en tu public function accessRules(), otra cosa todo campo nuevo que agregas debes ponerlo en el modelo te recomiendo de que luego q pongas las tablas como te dije crees de nuevo con el gii generator tu modelo y tu crud de cada tabla

prueba el codigo y me dices si manda error

hay problema en mantener los id de cada tabla con ID? lo digo porque quien me pidio esto. me especifico que queria que todos los identificadores de todas las tablas se llamaran “id”. :blink:

para serte sincero no se :D pero yo creo q por orden debe cada id tener algo q permita reconocerlo en la aplicación, por otro lado pues si te fijas en el dropdown hay un ‘update’ … seria que lo reemplazaras por el id del campo en el cual quieres que se haga el update ejemplo : ‘update’=>’#city_id’ , tendrías que ver el id de tu dropdown que vas a actualizar y reeemplazarlo en el ejemplo :confused: … aunque sigo recomendando q por orden es mejor como te digo :confused: o te vas a confundir en el momento que quieras llamar el id :confused: te tomara mas tiempo reconocer de donde proviene

Intenté diferenciando los id a traves de las relaciones


idparroquia0.idmunicipio0.idestado0.id

pero me da error. ya no se que hacer… rehacer el modelo, las vistas el controllador, es comenzar desde cero T_T

pon aquí los modelos de las tablas relacionadas y el controlados de tu vista y pon el error q te esta sacando

Aqui los modelos de las tablas relacionadas

Estado


<?php


/**

 * This is the model class for table "tbl_estado".

 *

 * The followings are the available columns in table 'tbl_estado':

 * @property integer $id

 * @property string $codedo

 * @property string $estado

 * @property integer $estatusreg

 *

 * The followings are the available model relations:

 * @property TblMunicipio[] $tblMunicipios

 */

class TblEstado extends CActiveRecord

{

	/**

	 * @return string the associated database table name

	 */

	public function tableName()

	{

		return 'tbl_estado';

	}


	/**

	 * @return array validation rules for model attributes.

	 */

	public function rules()

	{

		// NOTE: you should only define rules for those attributes that

		// will receive user inputs.

		return array(

			array('codedo, estado', 'required'),

			array('estatusreg', 'numerical', 'integerOnly'=>true),

			// The following rule is used by search().

			// @todo Please remove those attributes that should not be searched.

			array('id, codedo, estado, estatusreg', 'safe', 'on'=>'search'),

		);

	}


	/**

	 * @return array relational rules.

	 */

	public function relations()

	{

		// NOTE: you may need to adjust the relation name and the related

		// class name for the relations automatically generated below.

		return array(

			'tblMunicipios' => array(self::HAS_MANY, 'TblMunicipio', 'idestado'),

		);

	}


	/**

	 * @return array customized attribute labels (name=>label)

	 */

	public function attributeLabels()

	{

		return array(

			'id' => 'numero identificador de estado',

			'codedo' => 'codigo del estado correspondiente',

			'estado' => 'Estado',

			'estatusreg' => 'estatus en el que encuentra el registro (activo - inactivo)',

		);

	}


	/**

	 * Retrieves a list of models based on the current search/filter conditions.

	 *

	 * Typical usecase:

	 * - Initialize the model fields with values from filter form.

	 * - Execute this method to get CActiveDataProvider instance which will filter

	 * models according to data in model fields.

	 * - Pass data provider to CGridView, CListView or any similar widget.

	 *

	 * @return CActiveDataProvider the data provider that can return the models

	 * based on the search/filter conditions.

	 */

	public function search()

	{

		// @todo Please modify the following code to remove attributes that should not be searched.


		$criteria=new CDbCriteria;


		$criteria->compare('id',$this->id);

		$criteria->compare('codedo',$this->codedo,true);

		$criteria->compare('estado',$this->estado,true);

		$criteria->compare('estatusreg',$this->estatusreg);


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}


	/**

	 * Returns the static model of the specified AR class.

	 * Please note that you should have this exact method in all your CActiveRecord descendants!

	 * @param string $className active record class name.

	 * @return TblEstado the static model class

	 */

	public static function model($className=__CLASS__)

	{

		return parent::model($className);

	}


	protected function beforeSave() 

	{

	    $this->estado = strtoupper($this->estado);

	    return parent::beforeSave();

	}


}



Municipio


<?php


/**

 * This is the model class for table "tbl_municipio".

 *

 * The followings are the available columns in table 'tbl_municipio':

 * @property integer $id

 * @property integer $idestado

 * @property string $codmun

 * @property string $municipio

 * @property integer $estatusreg

 *

 * The followings are the available model relations:

 * @property TblParroquia[] $tblParroquias

 * @property TblEstado $idestado0

 */

class TblMunicipio extends CActiveRecord

{

	/**

	 * @return string the associated database table name

	 */

	public function tableName()

	{

		return 'tbl_municipio';

	}


	/**

	 * @return array validation rules for model attributes.

	 */

	public function rules()

	{

		// NOTE: you should only define rules for those attributes that

		// will receive user inputs.

		return array(

			array('idestado, codmun, municipio', 'required'),

			array('idestado, estatusreg', 'numerical', 'integerOnly'=>true),

			// The following rule is used by search().

			// @todo Please remove those attributes that should not be searched.

			array('id, idestado, codmun, municipio, estatusreg', 'safe', 'on'=>'search'),

		);

	}


	/**

	 * @return array relational rules.

	 */

	public function relations()

	{

		// NOTE: you may need to adjust the relation name and the related

		// class name for the relations automatically generated below.

		return array(

			'tblParroquias' => array(self::HAS_MANY, 'TblParroquia', 'idmunicipio'),

			'idestado0' => array(self::BELONGS_TO, 'TblEstado', 'idestado'),

		);

	}


	/**

	 * @return array customized attribute labels (name=>label)

	 */

	public function attributeLabels()

	{

		return array(

			'id' => 'numero identificador de municipio',

			'idestado' => 'Idestado',

			'codmun' => 'codigo correspondiente a este municipio',

			'municipio' => 'Municipio',

			'estatusreg' => 'estatus en el que encuentra el registro (activo - inactivo)',

		);

	}


	/**

	 * Retrieves a list of models based on the current search/filter conditions.

	 *

	 * Typical usecase:

	 * - Initialize the model fields with values from filter form.

	 * - Execute this method to get CActiveDataProvider instance which will filter

	 * models according to data in model fields.

	 * - Pass data provider to CGridView, CListView or any similar widget.

	 *

	 * @return CActiveDataProvider the data provider that can return the models

	 * based on the search/filter conditions.

	 */

	public function search()

	{

		// @todo Please modify the following code to remove attributes that should not be searched.


		$criteria=new CDbCriteria;


		$criteria->compare('id',$this->id);

		$criteria->compare('idestado',$this->idestado);

		$criteria->compare('codmun',$this->codmun,true);

		$criteria->compare('municipio',$this->municipio,true);

		$criteria->compare('estatusreg',$this->estatusreg);


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}


	/**

	 * Returns the static model of the specified AR class.

	 * Please note that you should have this exact method in all your CActiveRecord descendants!

	 * @param string $className active record class name.

	 * @return TblMunicipio the static model class

	 */

	public static function model($className=__CLASS__)

	{

		return parent::model($className);

	}

}



Parroquia


<?php


/**

 * This is the model class for table "tbl_parroquia".

 *

 * The followings are the available columns in table 'tbl_parroquia':

 * @property integer $id

 * @property integer $idmunicipio

 * @property string $codpar

 * @property string $parroquia

 * @property integer $estatusreg

 *

 * The followings are the available model relations:

 * @property TblMunicipio $idmunicipio0

 * @property TblEstructura[] $tblEstructuras

 * @property TblDependencias[] $tblDependenciases

 */

class TblParroquia extends CActiveRecord

{

	/**

	 * @return string the associated database table name

	 */

	public function tableName()

	{

		return 'tbl_parroquia';

	}


	/**

	 * @return array validation rules for model attributes.

	 */

	public function rules()

	{

		// NOTE: you should only define rules for those attributes that

		// will receive user inputs.

		return array(

			array('idmunicipio, codpar, parroquia', 'required'),

			array('idmunicipio, estatusreg', 'numerical', 'integerOnly'=>true),

			// The following rule is used by search().

			// @todo Please remove those attributes that should not be searched.

			array('id, idmunicipio, codpar, parroquia, estatusreg', 'safe', 'on'=>'search'),

		);

	}


	/**

	 * @return array relational rules.

	 */

	public function relations()

	{

		// NOTE: you may need to adjust the relation name and the related

		// class name for the relations automatically generated below.

		return array(

			'idmunicipio0' => array(self::BELONGS_TO, 'TblMunicipio', 'idmunicipio'),

			'tblEstructuras' => array(self::HAS_MANY, 'TblEstructura', 'idparroquia'),

			'tblDependenciases' => array(self::HAS_MANY, 'TblDependencias', 'idparroquia'),

		);

	}


	/**

	 * @return array customized attribute labels (name=>label)

	 */

	public function attributeLabels()

	{

		return array(

			'id' => 'numero identificador de  parroquia\r\n\r\n',

			'idmunicipio' => 'Idmunicipio',

			'codpar' => 'codigo correspondiente a la parroquia',

			'parroquia' => 'nombre de la parroquia',

			'estatusreg' => 'estatus en el que encuentra el registro (activo - inactivo)',

		);

	}


	/**

	 * Retrieves a list of models based on the current search/filter conditions.

	 *

	 * Typical usecase:

	 * - Initialize the model fields with values from filter form.

	 * - Execute this method to get CActiveDataProvider instance which will filter

	 * models according to data in model fields.

	 * - Pass data provider to CGridView, CListView or any similar widget.

	 *

	 * @return CActiveDataProvider the data provider that can return the models

	 * based on the search/filter conditions.

	 */

	public function search()

	{

		// @todo Please modify the following code to remove attributes that should not be searched.


		$criteria=new CDbCriteria;


		$criteria->compare('id',$this->id);

		$criteria->compare('idmunicipio',$this->idmunicipio);

		$criteria->compare('codpar',$this->codpar,true);

		$criteria->compare('parroquia',$this->parroquia,true);

		$criteria->compare('estatusreg',$this->estatusreg);


		return new CActiveDataProvider($this, array(

			'criteria'=>$criteria,

		));

	}


	/**

	 * Returns the static model of the specified AR class.

	 * Please note that you should have this exact method in all your CActiveRecord descendants!

	 * @param string $className active record class name.

	 * @return TblParroquia the static model class

	 */

	public static function model($className=__CLASS__)

	{

		return parent::model($className);

	}

}



este es mi form_


<!-- ************************************************************************************************ -->

<!-- ************************************************************************************************ -->

<!-- ************************************************************************************************ -->


<div class="row">

<?php echo $form->labelEx($model,'Estado'); ?>


 <?php 

              echo $form->dropDownList($model,'idparroquia0.idmunicipio0.idestado0.id',CHtml::listData(TblEstado::model()->findAll(),'id','estado'),

                        array(

                            'ajax' => array(

                            'type' => 'POST',

                            'url' => CController::createUrl('TblEstructura/Selectmunicipio'),

                            'update' => '#'.CHtml::activeId($model,'id_municipio'), /* deberias cambiar tus id y renombrarlos decuardo a tu tabla ejem: tabla municipios seria id_municipio, tabla estado seria id_estado de tal manera que no te saque errore por poner el mismo nombre a un campo*/

                        ),'prompt' => 'Seleccione un Estado...'

                  )

              );

        ?>


 </div>


<div class="row">

  <?php echo $form->labelEx($model,'Municipio'); ?>

 


    <?php 

    		  echo $form->dropDownList($model,'idparroquia0.idmunicipio0.id',CHtml::listData(TblMunicipio::model()->findAll(),'id','Municipio'),

                        array(

                            'ajax' => array(

                            'type' => 'POST',

                            'url' => CController::createUrl('TblEstructura/SelectParroquia'),

                            'update' => '#'.CHtml::activeId($model,'id_parroquia'),

                        ),

                  )

              );

        ?>        

 </div>


<div class="row">

    <?php echo $form->labelEx($model,'Parroquia'); ?>


    <?php echo $form->dropDownList($model,'idparroquia',array()); ?>


</div>




<!-- ************************************************************************************************ -->

<!-- ************************************************************************************************ -->

<!-- ************************************************************************************************ -->



El error me dice:


 La propiedad "TblEstructura"."idparroquia0.idmunicipio0.idestado0.id" no se encuentra definida.


/var/www/yii/framework/db/ar/CActiveRecord.php(145)


133      */

134     public function __get($name)

135     {

136         if(isset($this->_attributes[$name]))

137             return $this->_attributes[$name];

138         elseif(isset($this->getMetaData()->columns[$name]))

139             return null;

140         elseif(isset($this->_related[$name]))

141             return $this->_related[$name];

142         elseif(isset($this->getMetaData()->relations[$name]))

143             return $this->getRelated($name);

144         else

145             return parent::__get($name);

146     }

Se que esta mal llamdo el id del estado y municipio pero no se de que otra manera llamarlo. ademas recuerden que los ID de las tablas se llaman "id" ya cuando son claves foraneas se llaman "idtabla" (por ejemplo)