- EL CONOCIMIENTO ES Y DEBE SER LIBRE -

lunes, julio 12, 2010

Integrando jQuery, Gwt y Php

La idea de este Post no es realizar un  tutorial, sino una guía de introducción que permitan al programador de una manera rápida ver de qué trata el asunto. Al final se muestra un pequeño ejemplo junto con su respectivo video-guía de implementación para que cualquiera con algo de entusiasmo pueda realizarlo.

La integración  de jQuery a GWT se consigue a través de JSNI(JavaScript Native Interfaze) y la integración de GWT con PHP lo realizaremos a través de RestDataSource (librería de SmartGWT).
Lectura Obligada: GWT Style, Configuration and JSNI Reference

Introducción
El JSNI nos brinda la posibilidad de utilizar métodos Java que contengan código JavaScript, estos métodos de Java deberán de tener el modificador  “native”, con este modificador le comunicamos al compilador que no valide su contenido.

Llamado métodos JavaScript de Java
Llamar métodos JavaScript de Java es bastante sencillo, solo tienes que tener en cuenta los alias de los objetos JavaScript:  “window” y “document”,  que son:  “$wnd” y “$doc” respectivamente.
//Capturamos la imagen snapshot del video
 public native String getImageUrl(String cad)/*-{ 
  //aca llamamos a JavaScript de Java
  return $wnd.$.jYoutube(cad);  
 }-*/;


Llamando métodos Java de JavaScript
Llamar métodos Java de JavaScript implica el manejo de una sintaxis especial.
[instance-expr.]@class-name::method-name(param-signature)(arguments)
La explicación de esta sintaxis la encuentran  acá. (Para encontrar el “class-name” use el autocompletado  de Eclipse, y no se hagan tanto rollo con eso de “fully qualified name”).
//Mostramos la imagen sin efecto 
 public void ShowImage(String url)
 {
  ImgPrincipal.setUrl(url);
 }
  
   //Ocultamos la imagen con efecto SLOW 
 public native void HideImage(String url)/*-{ 
  var tempThis=this;  
  $wnd.$("#idImgPrincipal").hide('slow',function(){          
    //aca llamamos a Java de JavaScript
    tempThis.@jsni.pck.client.Jsni::ShowImage(Ljava/lang/String;)(url);
    $wnd.$("#idImgPrincipal").show('fast');
  });    
 }-*/;
No está de más mencionar que “ShowImage” y “HideImage” pueden ser llamados desde cualquier parte de nuestra aplicación Java.


Pasando valores entre Java y JavaScript y viceversa
Este tema no es complicado, pero en el documento del inicio del Post hay una muy buena guía sobre este tema.

Integración con PHP
Se puede utilizar la integración con php a través de RequestBuilder, pero nosotros utilizaremos RestDataSource que como verán en el ejemplo nos brinda la data ya formateada, de modo tal que su utilización se hace mucho más fácil; ya que, no tenemos que lidear con el formato JSON directamente.
//preparamos para la captura de la data
  OperationBinding fetch = new OperationBinding();
  fetch.setOperationType(DSOperationType.FETCH);
  fetch.setDataProtocol(DSProtocol.POSTPARAMS);
   
  RestDataSource data=new RestDataSource();  
  data.setOperationBindings(fetch);
  data.setDataFormat(DSDataFormat.JSON);
  data.setFetchDataURL("fetch.php");
  //capturamos la data asincronamente
  data.fetchData(null, new DSCallback(){
   @Override
   public void execute(DSResponse response, Object rawData,
     DSRequest request) {
     
     OnExecuteFetch(response.getData());  
   } 
  }); 
Integración con JQUERY
La integración es bastante sencilla sola haga referencia a los scripts deseados

    
    
El Ejemplo
Normalmente los métodos de Jquery  tienen una función de Callback(Retrollamada) al concluir alguna operación :
$('.tag').hide(“slow”,function(){
  
  alert(‘el tag fue ocultado’)

 });
La idea del ejemplo es mostrar como mediante JSNI podemos llamar al método “hide” y como implementar la función de Callback (Retrollamada) todo dentro de GWT.

Ahora explicaremos algo del código fuente "Jsni.java". En la línea 9 el método “ShowImage” muestra una imagen dada una url, en la línea 16 el método “HideImage” oculta una imagen dada una url , para cumplir con su objetivo hace uso de Jquery con su método “hide” (creando el efecto de ocultamiento)que a su vez realiza una retrollamada (Callback) al ocultar la imagen, al ocultar la imagen lanza la nueva imagen por mostrar llamando al método “ShowImage”.

La integración con PHP podemos verlo en la línea 83, donde se le brinda la ubicación de: “fetch.php”. La data se captura asíncronamente, una vez que la data llega al cliente se lanza el evento “OnExecuteFetch” (en la línea 90).


//Codigo fuente Jsni.java
 
public class Jsni implements EntryPoint {

 private  Image ImgPrincipal=null;
 private VerticalPanel ImgVertical=null;
 
 
   //Mostramos la imagen sin efecto 
 public void ShowImage(String url)
 {
  ImgPrincipal.setUrl(url);
 }
 
   //Ocultamos la imagen con efecto SLOW 
 public native void HideImage(String url)/*-{ 
  var tempThis=this;  
  $wnd.$("#idImgPrincipal").hide('slow',function(){          
    //aca llamamos a Java de JavaScript
    tempThis.@jsni.pck.client.Jsni::ShowImage(Ljava/lang/String;)(url);
    $wnd.$("#idImgPrincipal").show('fast');
  });    
 }-*/;
 
   //Capturamos la imagen snapshot del video
 public native String getImageUrl(String cad)/*-{ 
  //aca llamamos a JavaScript de Java
  return $wnd.$.jYoutube(cad);  
 }-*/;

   //Evento lanzado cuando se ejecuta la Fetch
 public void OnExecuteFetch(Record[] row)
 {
  for(Record tempRow:row){
   
   final String url=tempRow.getAttributeAsString("url");
   String titulo=tempRow.getAttributeAsString("titulo");
   
   HorizontalPanel hp=new HorizontalPanel();
   Image img=new Image(getImageUrl(url));
   img.setSize("50px", "50px");
   
   HTML label=new HTML(titulo);
    label.addClickHandler(new ClickHandler(){ 
     @Override
     public void onClick(ClickEvent event) {
     
      HideImage(getImageUrl(url));
      
     }});
  
   hp.add(img);
   hp.add(label);
   
   ImgVertical.add(hp);
  } 
 }
 
  // Enlaza los Widgets a la Interfaz 
 public void EnlazaInterfaz()
 {
  ImgPrincipal=new Image();
  ImgPrincipal.setSize("250px", "250px");
  
  ImgVertical=new VerticalPanel();
  
  RootPanel.get("idImgPrincipal").add(ImgPrincipal);
  RootPanel.get("idImgVertical").add(ImgVertical);
 }
 public void onModuleLoad() {
  
  //Enlazamos al HTML
  EnlazaInterfaz();
  
  //preparamos para la captura de la data
  OperationBinding fetch = new OperationBinding();
  fetch.setOperationType(DSOperationType.FETCH);
  fetch.setDataProtocol(DSProtocol.POSTPARAMS);
  
  RestDataSource data=new RestDataSource();  
  data.setOperationBindings(fetch);
  data.setDataFormat(DSDataFormat.JSON);
  data.setFetchDataURL("fetch.php");
  //capturamos la data asincronamente
  data.fetchData(null, new DSCallback(){
   @Override
   public void execute(DSResponse response, Object rawData,
     DSRequest request) {
    
     OnExecuteFetch(response.getData());  
   } 
  }); 
 
 }//end function
}//end class
/*
* Codigo fuente de fetch.php
*/
$data=array();
$data[0]['id']=1;
$data[0]['descripcion']='inaguracion en el año 3000';
$data[0]['url']='http://www.youtube.com/watch?v=dz1GpyU6YKQ';
$data[0]['titulo']='INAGURACION SAN FRANK';

$data[1]['id']=2;
$data[1]['descripcion']='inaguracion en el año 2009';
$data[1]['url']='http://www.youtube.com/watch?v=9-FQly3ETP8';
$data[1]['titulo']='INAGURACION SAN JOSE';

$data[2]['id']=3;
$data[2]['descripcion']='inaguracion en el año 2010';
$data[2]['url']='http://www.youtube.com/watch?v=wqE4SdrIu1E';
$data[2]['titulo']='INAGURACION SAN JUMANOR';

$mensaje=array();
$mensaje['response']['status']=0;
$mensaje['response']['data']=$data;

echo json_encode($mensaje);
Los Widgets serán enlazados a los ids: “idImgVertical” y “idImgPrincipal”, como se muestra en el código fuente “Jsni.html”
<!--Codigo fuente Jsni.html-->
<h1>Aplicando JSNI con PHP</h1><table style="width: 605px;" border="1" height="343"><tbody>
<tr><td height="160" width="166"><div id="idImgVertical" style="height: 250px;"></div></td><td width="127"></td>      <td width="290"><div id="idImgPrincipal" style="height: 250px; width: 250px;"></div></td>   </tr>
</tbody> </table>
En este video-guía  se asume que ha creado un proyecto con el nombre “jsni” y paquete “jsni.pck”. Adicionalmente debe de tener instalado GWT 2.0.3 y SmartGWT 2.2. En la carpeta war del proyecto tendrá que crear una carpeta nombrándola como “Scripts” en donde deberá de colocar los archivos “JQuery  1.4.2.js” y “JYouTube.js”.

9 comentarios:

Anónimo dijo...

Hola,

Estoy siguiendo este ejemplo para crear una aplicación más compleja. Ocurre que si en el archivo fetch.php colocas una sentencia require o include la página no carga nada. No sé por qué ocurre esto. ¿Alguien sabe por qué?

Gracias y enhorabuena por el artículo.

Jorge Cotrado dijo...

Hola,
1)Que mensaje de error?, PHP siempre te muestra el error !!!! (En caso el error sea en el Servidor)

2)Instala FIREBUG, con esto podras ver la data que envia el servidor.
(El cliente esta esperando una estructura json,si estas enviando algo que es diferente a esa estructura no te mostrara nada-no carga nada-)

3)Copia algo de codigo, la verdad necesito mas informacion para ayudarte

Saludos, Jumanor

Edu dijo...

Hola,

Resulta que tenía errores en el PHP que quería incluir. (He visto los mensajes de error accediendo desde el navegador a la ruta exacta del PHP, desde el HTML principal se queda en blanco y no se muestra el error).

Ya aprovecho para indicar que en el fetch.php, para evitar problemas con tildes se debería utilizar esta función (volviendo a tu ejemplo):

$data[0]['descripcion']=utf8_encode('inaguración en el año 3000');

Saludos y gracias.

Jorge Cotrado dijo...

Si tus arhivos php estan en formato utf-8 y tu BD tbm esta en UTF-8 y al index.php le agregas:

<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />

no tendras nesecidad de usar la funcion utf8_enconde.

Saludos.

Edu dijo...

Sí, tengo todos los ficheros del proyecto en UTF-8, así como la BD y el meta añadido. Pero parece que hay ocasiones en que no es suficiente (Goggleando he visto mucha gente que tiene el mismo problema).

Aún así, con esa función estamos a salvo de este error con independencia de la codificación de los fuentes.

Saludos.

Jorge Cotrado dijo...

OK, a tener en cuenta !!!!

Anónimo dijo...

Es evidente que hay mucho que aprender acerca de esto. Creo que hizo algunas cosas buenas en características también. Sigue trabajando, gran trabajo!

Anónimo dijo...

Tener un día DINAMITA mi amigo!

Anónimo dijo...

Necesidad de mantener las pruebas de mi blog. No funciona como yo lo quiero todavía. Thx por el tema. Tal vez esto lo mío para mirar mejor.