miércoles, 19 de diciembre de 2012

SCRIPT VS CClientScript


SCRIPT VS CClientScript (Yii Framework)

En Yii Framework es posible insertar <SCRIPT> en cualquier parte, no hay limitantes, pero viene a la ayuda CClientScript, la cual trae extremos beneficios, aunque a veces sea mas rápido solo insertar <script>...bla...</script>, no siempre será esta la mejor opcion, aqui es donde entra CClientScript.

Pongo un ejemplo, CListView.

Bien sabes que CListView recibe un array de datos (de "registros" para ser mas familiar), en forma de array de arrays para poder hacer paginación, esto no viene al caso del ejemplo, asi que limitemonos a pensar en que CListView toma un array y por cada elemento llamara a una vista en la cual "renderizará" al registro de ese array.

// file:   ..protected/views/car/index.php
<div class='cars'>
$this->widget('zii.widgets.CListView',
  array('dataProvider'=>Car::model()->search(), 'view'=>'applications.view.car._car'),

);
</div>

Cada "Car"  sera renderizado por una vista: "applications.views.car._car" (../protected/views/car/_car.php) la cual dice:

// file:   ../protected/views/car/_car.php
<?php
  // $data:  instancia de Car

  echo "<b>".$data->name."</b>";
?>


Como resultado tendrás una pagina html que dira:

<html>
   <div class='cars'>

   <b>chevrolet aveo</b><b>chevrolet malibu</b><b>chevrolet spark</b>
   </div>

</html>

Hasta aqui vamos bien, no pretendo explicar a CListView, sino mostrar como CClientScript se va a portar aqui en contraparte con el uso de <SCRIPT>.

Insertando una pieza de javascript usando: <SCRIPT> VS CClientScript.
Supongamos que queremos agregar un evento click a cada <B> usando jQuery, tenemos dos opciones, o usamos SCRIPT o usamos CClientScript. aqui verás la gran diferencia:

Usando SCRIPT en index.php:  (incorrecto desde el punto de vista de modelado, correcto si quieres hacer un desastre)

// file:   ../protected/views/car/index.php
<div class='cars'>
$this->widget('zii.widgets.CListView',
  array('dataProvider'=>Car::model()->search(), 'view'=>'applications.view.car._car'),

);
</div>
<script>
   $('.cars b').each(function(){  

        $(this).click(function(){ 
             alert("hola "+$(this).html()); 
         }); 
    });
</script>


Si decides usar <SCRIPT> como muestro arriba, tendrás que ponerlo en "protected/views/car/index.php" ya que de lo contrario si lo pones en _car.php el script se repetirá N veces (segun N registros tengas), causando problemas, incluso dejando de funcionar, pero este no es el sitio mas correcto porque:
¿ que le importa a index.php acerca de cómo _car.php pinta al carro ?...no le importa...no es su negocio.


Beneficios usando CClientScript:

Desde el punto de vista de "Modelado" es sano y  limpio que la funcionalidad del carro este en _car.php y no en index.php.   El widget que presenta la lista de carros es una cosa, y el carro otra.

Primero dejemos a index.php como estaba al inicio:

// file:   ../protected/views/car/index.php
<div class='cars'>
$this->widget('zii.widgets.CListView',
  array('dataProvider'=>Car::model()->search(), 'view'=>'applications.view.car._car'),

);
</div>

ahora, vayamos a _car.php y demosle la funcionalidad:


CASO ERRONEO: (Usando SCRIPT)
razón:  <script> se repetirá N veces, dejando de funcionar, y no vamos a perder la maravilla de jQuery por andar reparando esto al estilo de los años 80....dios. Simplemente asi no se usa, y pasamos a CClientScript.


// file:   ../protected/views/car/_car.php
<?php
  // $data:  instancia de Car

  echo "<b>".$data->name."</b>";
?>

<script>
   $('.cars b').each(function(){  

        $(this).click(function(){ 
             alert("hola "+$(this).html()); 
         }); 
    });
</script>


CASO CORRECTO: (usando CClientScript)
// file:   ../protected/views/car/_car.php
<?php
  // $data:  instancia de Car

  echo "<b>".$data->name."</b>";
?>

<?php

Yii::app()->getClientScript()->registerScript( "car_script",
 "
   $('.cars b').each(function(){  
        $(this).click(function(){ 
             alert("hola "+$(this).html()); 
         }); 
    });
"
,CClientScript::POS_END);
?>


¿ Por qué esta forma de insertar el script es correcta ?, porque CClientScript se preocupa de NO REPETIR el script si su id ya fue incrustado: "car_script".  Verás en consecuencia que la pagina obtenida incrustará el script al final debido a la opcion CClientScript::POS_END.

Esto causará que donde quiera que uses la vista _car.php esta traiga la funcionalidad indicada, no importando si fue lanzada por index.php (el widget de CListView que lista todos los carros) o si estas mostrando un carro en particular usando:

Podrías invocar la vista _car.php no solo desde el widget (index.php) sino desde cualquier vista sin que pierda la funcionalidad !!

$mycar = Car::model()->findByPk('ABC-123');
$this->renderPartial(
'application.views.car._car.php', array('data'=>$mycar));

resutado ? siempre que muestre es carro, el mensajito "hola xxxx" saldrá, sin importar como se listo el carro.

1 comentario:

  1. Una de las mejores explicaciones, fácil y muy clara de como usar CClientScript :)

    Don Royus en Facebook ;)

    ResponderEliminar