Ramiro Anacona Meneses avatar Ramiro Anacona Meneses committed 8dbabfc

Add Source.

Comments (0)

Files changed (6)

EDropDownsDependents.php

+<?php
+
+class EDropDownsDependents extends CInputWidget implements EYuiActionRunnable {
+
+  public $defaultAction = '/site/dropdowns'; //Se configura el acion en siteController.php asi: 'dropdowns' => array('class' => 'ext.EDropDownsDependents.EDropDownsDependentsAction')
+  public $dataModel;                //Modelo de donde se sacaran las opciones para el dropDownList puede ser String nombre del Modelo o array(key => value) Si es un segundo dropDown dependiente pon un array()
+  public $title = 'title';          //Nombre del campo de la tabla que se usara para mostrar en las opciones del dropDownList
+  public $targetModel;              //Nombre del modelo para consultar las opciones para el segundo dropDownList
+  public $targetField;              //Nombre del campo que guarda la relacion con la tabla superior
+  public $targetTitle = 'title';    //Nombre del campo que se usara para mostrar en las opciones del segundo dropDownList
+  public $dropDownListTarget;       //Nombre de la propiedad en el modelo actual ej: $form->dropDownList($model, 'codimuni', array()); "codimuni"
+  public $showImageCharging = true; //Booleano muestra o no una imagen de cargando junto al lado derecho del dropDownList
+  public $htmlOptions = array();    //htmlOptiones para el dropDownList ver http://www.yiiframework.com/doc/api/1.1/CHtml#dropDownList-detail
+  private $_assetsFolder;
+  private $_dataArrayOptions;
+
+  public function init() {
+    parent::init();
+
+    $this->registerCoreScripts();
+  }
+
+  public function run() {
+
+    if (is_array($this->dataModel)) {
+      $this->_dataArrayOptions = $this->dataModel;
+    }
+    else {
+      $dataModel = new $this->dataModel;
+      $this->_dataArrayOptions = CHtml::listData($dataModel->model()->findAll(), $dataModel->model()->tableSchema->primaryKey, $this->title);
+    }
+
+    print CHtml::activeDropDownList($this->model, $this->attribute, $this->_dataArrayOptions, $this->htmlOptions);
+
+    // preparamos algunas opciones para pasarselas al
+    // objeto javascript llamado DropDowns que crearemos
+    // mas abajo.
+    $options = CJavaScript::encode(array(
+           'firstField' => CHtml::activeId($this->model, $this->attribute),
+           'action' => Yii::app()->createUrl($this->defaultAction, array('nocache' => '')), // importante
+           'targetModel' => $this->targetModel,
+           'targetField' => $this->targetField,
+           'targetTitle' => $this->targetTitle,
+           'dropDownListTarget' => CHtml::activeId($this->model, $this->dropDownListTarget),
+           'showImageCharging' => $this->showImageCharging,
+           'imageCharging' => CHtml::image($this->_assetsFolder . '/loading.gif', 'Cargando', array('id' => 'image-charging-edropdownlist')),
+    ));
+
+    // insertamos el objeto Javascript DropDowns, el cual reside
+    // en un archivo JS externo (en los assets).
+    // le pasamos las opciones a su constructor con el objeto de 
+    // comunicar las dos piezas.
+    Yii::app()->getClientScript()->registerScript("dropdowns_corescript_" . $this->attribute, "new DropDowns({$options})");
+  }
+
+  public function registerCoreScripts() {
+
+    $localAssetsDir = dirname(__FILE__) . '/assets';
+    $this->_assetsFolder = Yii::app()->getAssetManager()->publish($localAssetsDir);
+
+    $cs = Yii::app()->getClientScript();
+
+    foreach (scandir($localAssetsDir) as $f) {
+      $_f = strtolower($f);
+      if (strstr($_f, ".js"))
+        $cs->registerScriptFile($this->_assetsFolder . "/" . $_f);
+      if (strstr($_f, ".css"))
+        $cs->registerCssFile($this->_assetsFolder . "/" . $_f);
+    }
+  }
+
+  public function runAction($action, $data) {
+
+    if ($action == 'dropdowns') {
+
+      //Creamos instancia del modelo del cual se optendran los datos para el segundo dropDownList
+      $model = new $data['targetModel'];
+      //Nombre del campo que guarda la relacion entre las dos tablas master-detail
+      $attribute = $data['targetField'];
+      //Capturamos el ID necesario para hacer la consutla.
+      $id = $data['id'];
+      //Nombre del campo que se usara para mostrar en el segundo dropDownList
+      $titleRelation = $data['targetTitle'];
+
+      //Creo un CHtml::listData es mas facil para luego recorrer retorna un array con clave valor
+      $list = CHtml::listData($model->model()->findAllByAttributes(array($attribute => $id)), $model->tableSchema->primaryKey, $titleRelation);
+
+      $options = NULL;
+      
+      //Creo opciones para el segundo dropDownList
+      foreach ($list as $key => $value) {
+        $options .= '<option value="' . $key . '">' . $value . '</option>';
+      }
+
+      //Imprimo resultado final, que sera tomado por la peticion ajax como resultado
+      print $options;
+    }
+  }
+
+}

EDropDownsDependentsAction.php

+<?php
+
+class EDropDownsDependentsAction extends CAction {
+
+  public function run() {
+
+    $inst = new EDropDownsDependents;
+    $inst->runAction($_POST['action'], $_POST);
+  }
+
+}

EYuiActionRunnable.php

+<?php
+/**
+ * EYuiActionRunnable class file.
+ *
+ *	Allow every based EYuiWidget-Based widget to respond a EYuiAction call.
+ *
+ *	@see
+ *		EYuiAction
+ *
+ * @author Christian Salazar <christiansalazarh@gmail.com>
+ * @link https://bitbucket.org/christiansalazarh/eyui
+ * @license http://opensource.org/licenses/bsd-license.php
+ */
+interface EYuiActionRunnable {
+
+	/**
+	* Method called whenever an EYui widget is invoked from an action int order to start query model.
+	*
+	*/
+	public function runAction($action,$data);
+}
+Widget que provee dropDownList dependientes
+===========================================
+
+por: Ramiro Anacona Meneses	<anacona16@gmail.com>
+
+Probado en: Yii  1.1.13
+
+EDropDownsDependents es un widget para [Yii Framework](http://www.yiiframework.com "Yii Framework") desarrollado para facilitar el uso de Combos dependientes en formularios.
+
+De una manera mas directa tenemos el siguiente ejemplo: Una relacion Maestro-Detalles entre Paises y Departamentos/Estados, y un Maestro-Detalle entre Departamentos/Estados y Municipios y asi segun se necesite.
+
+En esta imagen se puede ver el model ER entre las tablas
+
+![Master Detail Capture](https://bitbucket.org/anacona16/edropdownsdependents/downloads/master-detail.png "Master Detail Capture")
+
+Como se puede ver la tabla tb_cpoblados (Centro poblados, lo que seria pueblos mas pequeños dentro de municipios) al crear un nuevo registro de donde se requiera el codigo de un Municipio tendriamos que indicar el Departamento/Estado, pero listar todos los Departamentos/Estados en un solo DropDownList no seria lo mejor, por eso se utilizan Combos dependientes, siguiendo el ejemplo, para seleccionar un municipio anteriormente debi seleccionar un Departamento/Estado y para hacer esto ultimo debi antes seleccionar un Pais (El ejemplo lo hice con toda esta jerarquia para mostrar que EDropDownsDependents puede usarse en un mismo formulario varias veces)
+
+Al usar EDropDownsDependents para el ejemplo antes descrito, al final se mirara asi:
+
+![EDropDownsDependents Capture](https://bitbucket.org/anacona16/edropdownsdependents/downloads/screenshotDropDown.png "EDropDownsDependents Capture")
+
+INSTALAR
+--------
+
+## 1) Clonar el repositorio GIT
+
+    cd /home/myapp/protected/extensions
+    git clone https://anacona16@bitbucket.org/anacona16/edropdownsdependents.git
+
+    Si no usa GIT copie la carpeta completa edropdownsdependents en su carpeta de extensions
+
+### DESCARGA DIRECTA
+Por favor descargue el zip, y descomprima en /protected/extensions/edropdownsdependents
+
+## 2) Configure '/protected/config/main.php'
+
+    'import'=>array(
+      'application.models.*',
+      'application.components.*',
+      'ext.edropdownsdependents.*',   // <---
+    ),
+
+## 3) Configure la Accion
+
+Conecte el widget con la aplicacion usando un Action en SiteController (o uno diferente si lo prefiere)
+
+Por defecto, se usa:
+
+myapp/protected/controllers/SiteController.php
+
+IMPORTANTE:
+  Esta configuracion es requerida solamente una vez para todo el proyecto
+
+
+~~~
+[php]
+  public function actions()
+  {
+    return array(
+      'captcha'=>array(
+        'class'=>'CCaptchaAction',
+        'backColor'=>0xFFFFFF,
+      ),
+      'page'=>array(
+        'class'=>'CViewAction',
+      ),
+      'dropdowns'=>array(                       // <---
+        'class'=>'EDropDownsDependentsAction',  // <---
+      ),                                        // <---
+    );
+  }
+
+~~~
+
+## 4) Insertar y configurar el Widget
+
+~~~
+[php]
+<?php
+  $this->widget('ext.EDropDownsDependents.EDropDownsDependents', array(
+    'model' => $model,
+    'attribute' => 'codipais',
+    'dataModel' => array(170 => 'Colombia'), //Modelo para obtener las opciones para el dropDownList puede ser String nombre del Modelo o array(key => value) Si es un segundo dropDown se pone un array() !Vacio
+    'title' => 'descpais', //Nombre del campo de la tabla que se usara para mostrar en las opciones del dropDownList
+    'targetModel' => 'Departamentos', //Nombre del modelo para consultar las opciones para el segundo dropDownList
+    'targetField' => 'codipais', //Nombre del campo que guarda la relacion con la tabla superior
+    'targetTitle' => 'nombdepa', //Nombre del campo que se usara para mostrar en las opciones del segundo dropDownList
+    'dropDownListTarget' => 'codidepa', //Nombre de la propiedad en el modelo actual ej: $form->dropDownList($model, 'codimuni', array()); "codimuni"
+    'htmlOptions' => array(
+      'empty' => 'Seleccione Pais'
+   ),
+));
+?>
+~~~
+
+## 5) Otras Opciones
+
+~~~
+[php]
+'htmlOptions' => array(), // ver http://www.yiiframework.com/doc/api/1.1/CHtml#dropDownList-detail
+'showImageCharging' => true, //Muestra gif Cargando
+'defaultActionName' => '/site/dropdowns', //Si se cambia el Action se debe especificar en el controller
+~~~

assets/EDropDownsDependents.js

+// el codigo JS del widget
+var DropDowns = function(options) {
+
+    // esta funcion envia por ajax un comando POST asincrono
+    var ajaxcmd = function(action, postdata, callback) {
+
+        var result = false;
+
+        var nocache = function() {
+            var dateObject = new Date();
+            var uuid = dateObject.getTime();
+            return uuid;
+        };
+
+        jQuery.ajax({
+            url: action + nocache(),
+            type: 'post',
+            async: false,
+            data: postdata,
+            beforeSend: function() {
+                imageChargingEDropDownDenpendents('show');
+            },
+            success: function(data, textStatus, jqXHR) {
+                imageChargingEDropDownDenpendents('remove');
+
+                result = data;
+                if (callback != null)
+                    callback(true, data);
+            },
+            error: function(jqXHR, textStatus, errorThrown) {
+                imageChargingEDropDownDenpendents('remove');
+
+                callback(false, jqXHR.responseText);
+                return false;
+            },
+        });
+
+        return result;
+    }
+
+    // codigo que se ejecuta
+    // cuando el widget inicia:
+    // preparamos los controles:
+    $('#' + options.firstField).change(function() {
+
+        var id = $('#' + options.firstField + ' option:selected').val();
+        var idDropDownListTarget = $('#' + options.dropDownListTarget + ' option:selected').val();
+
+        if (idDropDownListTarget == '') {
+            var firstEmptyOption = $('#' + options.dropDownListTarget + ' option:first').html();
+        }
+
+        var datosPost = 'action=dropdowns' + '&id=' + id + '&targetModel=' + options.targetModel + '&targetField=' + options.targetField + '&targetTitle=' + options.targetTitle;
+
+        // enviamos la cosa al action via ajax
+        ajaxcmd(options.action, datosPost, function(ok, respuesta) {
+            if (ok == true) {
+                $('#' + options.dropDownListTarget).html(respuesta);
+                if (idDropDownListTarget == '') {
+                    $('#' + options.dropDownListTarget).prepend("<option value=''>" + firstEmptyOption + "</option>");
+                }
+            } else {
+                console.log('Error EdropDownList');
+            }
+        });
+    });
+
+    function imageChargingEDropDownDenpendents(type) {
+
+        if (options.showImageCharging == true) {
+
+            if (type == 'show') {
+                $('#' + options.firstField).after(options.imageCharging);
+            } else if (type == 'remove') {
+                $("img#image-charging-edropdownlist").remove();
+            }
+        }
+    }
+};
Added
New image
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.