Esta es la cuarta y última parte del proyecto “Sistema de Clientes” desarrollado en AIR con SQLite como administrador de base de datos. En la entrada anterior vimos cómo modificar y eliminar registros en la base de datos (clientesDB.sqlite) desde nuestra aplicación en AIR.
En esta ocasión veremos cómo realizar consultas de los registros en la base de datos; para esto crearemos una forma en la cual el usuario puede introducir el nombre, teléfono o correo del cliente que está buscando. Los resultados de esta consulta los escribiremos en un archivo HTML y lo mostraremos dentro del componente HTML (aprovechando el post que publiqué hace ya tiempo sobre cómo crear un archivo en AIR).
Parte 4: Consulta a la base de datos en SQLite con AIR
Recuerda que para mantener organizado el código de nuestro proyecto y para evitar que se pierdan con toda la información aquí mostrada, dividí el código del proyecto en archivos .as. Estos archivos estarán almacenados en la carpeta actionscript. La estructura de nuestro proyecto será la siguiente:
Imagen 1: Estructura de la aplicación
Todas las interfaces de este proyecto están incluidas en la carpeta componentes. La interfaz que en esta ocasión veremos es la del archivo ConsultaClientes.mxml. Esta interfaz funciona de la siguiente manera:
Al seleccionar la opción “Consultar…” del menú, se mostrará una forma con tres campos de texto, en donde el usuario podrá introducir el nombre, teléfono y correo del cliente que está buscando. Además, en la forma tendremos el botón de Mostrarel cual ejecutará la búsqueda. Los resultados serán mostrados dentro del rectángulo que ves en la parte de abajo de la imagen anterior.
Una vez que el usuario ejecute al búsqueda, si no se encontraron registros que coincidan con los datos buscados, el sistema mostrará dentro del archivo HTML la leyenda “No se encontraron resultados“. En caso contrario, el sistema mostrará los resultados de forma similar a la mostrada a continuación:
Dicho lo anterior, comenzaremos mostrando la estructura y el código del archivo ConsultaClientes.mxml:
- El ID del TextInput Nombre es nombre_txt
- El ID del TextInput Correo es correo_txt
- El ID del TextInput Teléfono es teléfono_txt
- El ID del componente HTML es HTMLLoader
El código de este archivo es el siguiente:
<?xml version="1.0" encoding="utf-8"?> <mx:Canvas show="abreConexion();" xmlns:mx="http://www.adobe.com/2006/mxml" width="100%" height="100%" backgroundColor="#FFFFFF"> <mx:Script source="../actionscript/ConsultarCliente.as"/> <mx:Label y="13" text="Consulta de Clientes" right="75" left="55" textAlign="center" fontWeight="bold" fontSize="14" fontFamily="Verdana" color="#F64507"/> <mx:Label y="61" text="Mostrar clientes por:" textAlign="left" fontWeight="normal" fontSize="12" fontFamily="Verdana" color="#000000" width="151" x="31" textDecoration="underline"/> <mx:Label y="89" text="Nombre:" textAlign="left" fontWeight="normal" fontSize="12" fontFamily="Verdana" color="#000000" width="83" x="62"/> <mx:Label y="119" text="Correo:" textAlign="left" fontWeight="normal" fontSize="12" fontFamily="Verdana" color="#000000" width="65" x="62"/> <mx:Label y="89" text="Teléfono:" textAlign="left" fontWeight="normal" fontSize="12" fontFamily="Verdana" color="#000000" width="74" x="285"/> <mx:Button x="415" y="119" label="Mostrar" click="generaConsulta();"/> <mx:HTML focusEnabled="false" id="HTMLLoader" borderStyle="solid" left="31" top="171" right="31" bottom="21"/> <mx:TextInput y="89" width="130" height="21" id="nombre_txt" fontSize="10" fontFamily="Verdana" x="123"/> <mx:TextInput y="89" width="130" height="21" id="telefono_txt" fontSize="10" fontFamily="Verdana" x="355"/> <mx:TextInput y="119" width="130" height="21" id="correo_txt" fontSize="10" fontFamily="Verdana" x="123"/> </mx:Canvas>
Observa en el código anterior que el tag principal de este archivo es <mx:Canvas> y no <mx:WindowedApplication>, esto es porque todas las interfaces que están dentro del directorio componentes las desplegaremos dentro de la aplicación principal (Sistema_Clientes.mxml); a la propiedad show del Canvas le estamos especificando que llame a la función abreConexion() una vez que se haya terminado de mostrar el componente. También observa cómo estamos incluyendo el código de ConsultarCliente.as:
<mx:Script source="../actionscript/ConsultarCliente.as"/>
Dentro del código del botón Mostrar hacemos la llamada a la función generaConsulta una vez que el usuario haya hecho click en dicho botón. El código de esta función (generaConsulta) y de la función principal (abreConexion) se encuentra dentro del archivo ConsultarCliente.as:
/* Importamos todas las librerías y clases que necesitamos. La clase HTMLTags la hice para establecer el código de cada elemento del archivo HTML, así como los estilos que usa dicho archivo; esta clase la veremos más adelante. */
import clases.HTMLTags;
import flash.data.SQLConnection;
import flash.events.SQLErrorEvent;
import flash.events.SQLEvent;
import flash.filesystem.File;
import flash.html.HTMLLoader;
import mx.controls.Alert;
/* Es importante establecer el tipo de codficación (encodeType) para que, al momento de escribir y generar el archivo, se muestren los acentos correctamente. */
private var _encodeType:String = "iso-8859-1";
private var conexion:SQLConnection;
private var database:File;
private var stream:FileStream = new FileStream(); /* Declaramos una variable de tipo FileStream para poder crear y escribir en el archivo */
private var htmlElements:HTMLTags = new HTMLTags();/* Este es un objeto de nuestra clase HTMLTags */
private var queryStatement:SQLStatement = new SQLStatement();
public function abreConexion():void {
database = new File(File.applicationStorageDirectory.nativePath + "\database\clientesDB.sqlite");
conexion = new SQLConnection();
conexion.addEventListener(SQLEvent.OPEN, dbAbrirConexion);
conexion.addEventListener(SQLErrorEvent.ERROR, dbErrorConexion);
conexion.open(database);
}
private function dbAbrirConexion(event:SQLEvent):void {
}
private function dbErrorConexion():void {
Alert.show("No se pudo conectar a la base de datos");
}
Después de haber importado las librerías necesarias y de haber declarado nuestras variables, escribimos el código de la función abreConexion. Esta función la hemos estado utilizando en las entradas anteriores, por lo que su código no debería causarte ruido.
Antes de ver el código de la función generaConsulta, mostraré el código de la clase HTMLTags:
package clases
{
public class HTMLTags
{
public function HTMLTags()
{
}
public function getEndTags():String {
var _texto:String = '</body>\n</html>\n';
return _texto;
}
public function getRulerTag():String {
var _texto:String = '<hr class="Ruler" />\n';
return _texto;
}
public function getFirstTags():String {
var _texto:String = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">\n' +
'<html xmlns="http://www.w3.org/1999/xhtml">\n' +
'<head>\n' +
'<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-2" />\n' +
'<title>Consulta: Tarjetas</title>\n' +
'<style>\n' +
'body {\n' +
' font:Arial, Helvetica, sans-serif;\n' +
' font-family:Arial, Helvetica, sans-serif;\n' +
' font-size:12px;\n' +
' margin-left:30px;\n' +
'}\n' +
'hr.Ruler {\n' +
' margin-left:-20px !important;\n' +
' color:#003366;\n' +
' border:1px solid #003366;\n' +
' background-color:#003366;\n' +
' width:800px;\n' +
'}\n' +
'.Estilo3 {\n' +
' color: #993300;\n' +
' font-weight: bold;\n' +
' font-size: 14px;\n' +
'}\n' +
'.Estilo4 {font-size: 12px; color: #666666;}\n' +
'.Tabla_Datos td {\n' +
' height:25px;\n' +
'}\n' +
'</style>\n' +
'</head>\n' +
'<body>\n';
return _texto;
}
public function getTitleTags(name:String):String {
var _texto:String = '<br /><span class="Estilo3">' + name + '</span><br /><br />\n';
return _texto;
}
public function getTable1Tags(nombre:String, direccion:String):String {
var _texto:String = '<table class="Tabla_Datos" width="700" border="0" cellspacing="0" cellpadding="0">\n' +
' <tr>\n' +
' <td><strong>Nombre:</strong></td>\n' +
' <td>' + nombre + '</td>\n' +
' <td><strong>Dirección:</strong></td>\n' +
' <td>' + direccion + '</td>\n' +
' </tr>\n';
return _texto;
}
public function getTable2Tags(telefono:String, correo:String):String {
var _texto:String = '' +
' <tr>\n' +
' <td><strong>Teléfono:</strong></td>\n' +
' <td>' + telefono + '</td>\n' +
' <td><strong>Correo:</strong></td>\n' +
' <td>' + correo + '</td>\n' +
' </tr>\n' +
'</table>\n';
return _texto;
}
}
}
Como pudiste observar en el código anterior, esta clase lo único que hace es regresarnos los tags del documento HTML que vamos a generar. Por ejemplo, la función getFirstTags nos regresa los primeros elementos que debe llevar el archivo HTML (los tags <html>, <head>, <meta> y los estilos que usaremos <style>). La función getTitleTags la mandaremos a llamar cada vez que recorramos un nuevo registro, le pasaremos como parámetro un texto de tipo “Cliente N” donde N es el valor de un contador que pondremos en el código (Cliente #1, Cliente #2, etc.) y nos regresará un texto con los tags y estilo que debe llevar. A la función getTable1Tags le estamos pasando como parámetro el nombre y la dirección del cliente, y ésta a su vez nos está regresando la información en forma de tabla con el código en HTML. Lo mismo sucede con la función getTable2Tags. La función getRulerTag nos regresa el tag <hr> para mostrar una línea horizontal. Por último, la función getEndTags nos regresa un texto con los tags que nos faltaban por cerrar (</body> y </html>).
Ahora veremos el código de generaConsulta. Presta atención en los comentarios que se encuentran dentro del código:
private function generaConsulta():void {
var prep:String = " WHERE ";
queryStatement.clearParameters();
queryStatement.sqlConnection = conexion;
var genericQuery:String = "SELECT * FROM cliente "; /* Seleccionamos todas las columnas del registro */
if(nombre_txt.text != "") { /* Si el usuario sí escribió algo en el campo de texto nombre_txt */
genericQuery += prep + " nombre LIKE '%" + nombre_txt.text + "%'"; /* Adjuntamos al query el valor del campo de texto nombre */
prep = " AND ";
}
if(correo_txt.text != "") { /* Si el usuario sí escribió algo en el campo de texto correo_txt */
genericQuery += prep + " email LIKE '%" + correo_txt.text + "%'"; /* Adjuntamos al query el valor del campo de texto correo */
prep = " AND ";
}
if(telefono_txt.text != "") { /* Si el usuario sí escribió algo en el campo de texto telefono_txt */
genericQuery += prep + " telefono LIKE '%" + telefono_txt.text + "%'"; /* Adjuntamos al query el valor del campo de texto telefono */
prep = " AND ";
}
genericQuery += " ORDER BY nombre asc"; /* Le especificamos al query que los resultados los ordene de manera ascendente de acuerdo al nombre del cliente */
queryStatement.text = genericQuery; // Asignamos la variable del query al SQLStatement
try {
queryStatement.execute(); // Ejecutamos la consulta
/* Este será el archivo HTML que estamos creando. Su nombre es ConsultaCliente.html y se encontrará dentro de la carpeta HTML */
var htmlFile:File = new File(File.applicationStorageDirectory.nativePath + "/HTML/ConsultaCliente.html");
if(stream != null) {
stream.close(); /* Cerramos el stream si es que existe */
}
stream = new FileStream();
stream.open(htmlFile, FileMode.WRITE); /* Abrimos el stream en modo de escritura */
stream.addEventListener(IOErrorEvent.IO_ERROR, writeIOErrorHandler); /* Establecemos un listener para detectar el evento */
var result:SQLResult = queryStatement.getResult(); /* Obtenemos los resultados regresados por la consulta */
if(result.data != null) { // Si existen resultados...
var numResults:int = result.data.length; // Determinamos el total de resultados regresados
stream.writeUTFBytes(htmlElements.getFirstTags()); /* Escribimos en el archivo el texto regresado por la clase HTMLTags en su función getFirstTags */
for (var i:int = 0; i < numResults; i++) // Hacemos un ciclo para recorrer todos los registros obtenidos
{
var row:Object = result.data[i];
row.nombre;
/* Esta parte entraría a un ciclo */
stream.writeMultiByte(htmlElements.getTitleTags("Cliente #" + (i + 1)), _encodeType);
stream.writeMultiByte(htmlElements.getTable1Tags(row.nombre, row.direccion), _encodeType);
stream.writeMultiByte(htmlElements.getTable2Tags(row.telefono, row.email), _encodeType);
stream.writeUTFBytes(htmlElements.getRulerTag());
/* Esta parte entraría a un ciclo */
}
stream.writeUTFBytes(htmlElements.getEndTags());
}
else {
stream.writeUTFBytes("No se encontraron resultados");
}
stream.close();
}
catch(error:SQLError) {
trace("Error: " + error.toString());
}
/* Si todo salió bien, ahora podremos mostrar el archivo html en nuestro HTMLLoader */
HTMLLoader.location = File.applicationStorageDirectory.nativePath + "/HTML/ConsultaCliente.html";
}
Observa que al final estamos especificando al control HTML (cuyo ID es HTMLLoader) el archivo HTML que debe mostrar (ConsultaCliente.html dentro de la carpeta HTML).
Hemos llegado al final de esta cuarta parte y de todas las entregas, no olvides bajar los archivos que se encuentran más abajo.
Enlaces recomendados:
» Working with local SQL databases
» Adobe® Flex® 3 Language Reference






Muy buen aporte, bien explicado……
Gracias…………….
aunque algunas funciones estan demas porq AIR tiene para validar campos por ejemplo pero muy bueno…
SALUDOD
Hi vicent … the encodeType its a reference for the html encode….
bye
Hi Vicente,
In that specific line of code I’m only declaring a variable, so we can name it different. This variable we use it to specify the charSet (Character set to use like “shift-jis”, “iso-8859-1″, etc.) when we want to write the stream in the file. In our case, we specify this charset (iso-8859-1) because we need to use accents and other special characters the spanish language have.
I hope this answer helps you.
You can find more about this in http://livedocs.adobe.com/flex/3/langref/flash/filesystem/FileStream.html#writeMultiByte().
Cheers!
Sorry, I don’t know how to write it in your language. I speak only english and portuguese. I’m interested to know what exact does the following code, and if you have any reference on this. Where do you use this variable _encodeType? (Is this a kind of a hack?)
Desculpe, eu não sei escrever no seu idioma. Eu somente falo Ingles e Portugues. Estou interessado em saber o que faz exatamente o código a seguir, e se você possui alguma referencia a respeito. Onde você usa essa variável _encodeType? (Trata-se de algum tipo de hack?)
code:
/* Es importante establecer el tipo de codficación (encodeType) para que, al momento de escribir y generar el archivo, se muestren los acentos correctamente. */
private var _encodeType:String = “iso-8859-1″;
Muito obrigado! Thank you very much!