Documente Academic
Documente Profesional
Documente Cultură
Para adaptar los formularios digitales modelados en el proceso y extender su funcionalidad mediante la utilizacin de Ajax para obtener datos del servidor dinmicamente, validar datos, filtro mltiple de combos, autocompletar datos, actualizar datos dinmicamente, etc. En GPA los Ajax se implementan mediante la utilizacin de reglas y el llamado de las mismas desde el javascript del formulario digital. Estos javascript incluyen la funcin executeComponentAjax: Esta funcin recibe los siguientes parmetros: {String} pCdComponent: Cdigo de componente a ejecutar {String} pCdComponentVersion: Versin del componente a ejecutar {Array} pLsComponentINParameters: Valores para los parmetros de entrada de componentes. Es un Array de la forma [InParamName1, InParamValue1, ..., InParamNameN, InParamValueN], donde InParami es el nombre del parmetro de entrada de la regla y lnParamValue es el valor que tomar dicho parmetro. No es necesario que de pasen los parmetros en el orden que estn definidos en la regla, ni tampoco que se defina un valor para cada parmetro (los parmetros no indicados en este arreglo, tomarn en la regla en valor por defecto (null)). {Function} pCallbackFunction Funcin que se ejecuta cuando el AJAX ejecut correctamente. Esta funcin recibir tres parmetros: el nodo raz del resultado de la ejecucin, un boolean para indicar si hubo errores o no, y pLsCallbackFunctionParameters. {Array} pLsCallbackFunctionParameters: Valores para pasar como parmetro a la funcin pCallbackFunction. {Boolean} pShowWaitMessage: Indica si se mostrar un mensaje de espera mientras se realiza la peticin al servidor. {String} pDsWaitMessage: Si se muestra un mensaje de espera, el valor de pDsWaitMessage ser el que se visualizar. Si no se especifica valor se mostrar un mensaje por defecto Ejecucin de la regla: executeComponentAjax(pCdComponent, pCdVersion, pLsComponentINParameters, pCallbackFunction, pLsCallbackFunctionParameters, pShowWaitMessage, pDsWaitMessage) Ejemplo asignacin de parmetros: var xFunction = function(pXMLRoot,pError,pParams){ // Cdigo a ejecutar cuando termine la ejecucin del Ajax; } executeComponentAjax(NombreDeLaRegla, Versin, *nombreParmetro1,valorParmetro1, nombreParmetro2, valorParmetro2+, xFunction, *valorParmetro1, valorParmetro2+, false, null);
No es necesario que la regla posea parmetros de entrada ni de salida, ni tampoco es obligatorio llamar a la regla con parmetros de entrada asignados (pLsComponentINParameters puede ser null). Una vez que el componente ejecut, y devolvi el resultado de la ejecucin, se debera procesar el resultado. En este momento se ejecuta la funcin asignado como parmetro. En esta funcin deberan estar todas acciones que se desearan hacer luego de que el ajax ejecut, por ejemplo, asignar el resultado de un parmetro de la regla a un campo, mostrar algn mensaje, ejecutar alguna otra funcin, etc. Se debe tener en cuenta que la ejecucin de ajax es asincrnica, por lo tanto, mientras el ajax se est ejecutando, no se bloquear la ejecucin de javascript. El resultado de la ejecucin del ajax ser una estructura XML. A continuacin se describir esta estructura, y luego, como recorrerla u obtener los valores que se deseen.
Dentro del tag Result, se encontrarn, dependiendo de la clase del parmetro de salida, las siguientes estructuras, que contendrn el valor de los parmetros de salida: Las clases simples soportadas son: Integer, Long, Float, Double, Boolean, BigDecimal, java.sql.Timestamp, java.sql.Time, java.sql.Date Las estructuras soportadas son: Mapas, Listas y arreglos. Se soportan hasta 8 niveles de anidamiento de estructuras String: <NombreParmetro class="java.lang.String" isNull="false" id="00000000000000000001" level="8">String</ NombreParmetro > Integer: < NombreParmetro class="java.lang.Integer" isNull="false" id="00000000000000000001" level="8">5</ NombreParmetro > Double: < NombreParmetro class="java.lang.Double" isNull="false" id="00000000000000000001" level="8">0.0</ NombreParmetro > BigDecimal: < NombreParmetro class="java.math.BigDecimal" isNull="false" id="00000000000000000001" level="8">0</ NombreParmetro > java.sql.Date: < NombreParmetro class="java.sql.Date" isNull="false" id="00000000000000000001" level="8">2012-06-01</ NombreParmetro > java.sql.Timestamp: < NombreParmetro class="java.sql.Timestamp" isNull="false" id="00000000000000000001" level="8">2012-0601 00:00:00.0</ NombreParmetro > Boolean:
< NombreParmetro class="java.lang.Boolean" isNull="false" id="00000000000000000001" level="8">false</ NombreParmetro > Null: < NombreParmetro isNull="true" level="8" /> Etc, etc etc. Para estructuras: Arreglo: < NombreParmetro class="java.lang.String[]" isNull="false" id="00000000000000000001" level="8"> <item class="java.lang.String" isNull="false" id="00000000000000000002" level="7">1</item> <item class="java.lang.String" isNull="false" id="00000000000000000003" level="7">String2</item> <item class="java.lang.String" isNull="false" id="00000000000000000004" level="7">Strign3</item> <item class="java.lang.String" isNull="false" id="00000000000000000005" level="7">String4</item> </ NombreParmetro > Lista: < NombreParmetro class="java.util.ArrayList" isNull="false" id="00000000000000000001" level="8"> <item class="java.lang.Integer" isNull="false" id="00000000000000000002" level="7">1</item> <item class="java.math.BigDecimal" isNull="false" id="00000000000000000003" level="7">0</item> <item class="java.lang.String" isNull="false" id="00000000000000000004" level="7">String</item> <item isNull="true" level="7" /> </ NombreParmetro > Mapa: < NombreParmetro class="java.util.HashMap" isNull="false" id="00000000000000000001" level="8"> <entry> <key class="java.lang.String" isNull="false" id="00000000000000000002" level="7">k4</key> <value class="java.lang.String" isNull="false" id="00000000000000000003" level="7">Valor4</value> </entry> <entry> <key class="java.lang.String" isNull="false" id="00000000000000000004" level="7">k3</key> <value class="java.lang.String" isNull="false" id="00000000000000000005" level="7">Valor3</value> </entry> <entry> <key class="java.lang.String" isNull="false" id="00000000000000000006" level="7">k1</key> <value class="java.lang.String" isNull="false" id="00000000000000000007" level="7">Valor1</value> </entry> <entry> <key class="java.lang.String" isNull="false" id="00000000000000000008" level="7">k2</key> <value class="java.lang.Integer" isNull="false" id="00000000000000000009" level="7">2</value> </entry> </ NombreParmetro > Mapa con otras Estructuras: < NombreParmetro class="java.util.HashMap" isNull="false" id="00000000000000000001" level="8"> <entry> <key class="java.lang.String" isNull="false" id="00000000000000000002" level="7">k4</key> <value class="java.util.ArrayList" isNull="false" id="00000000000000000003" level="7"> <item class="java.lang.Integer" isNull="false" id="00000000000000000004" level="6">1</item> <item class="java.math.BigDecimal" isNull="false" id="00000000000000000005" level="6">0</item> <item class="java.lang.String" isNull="false" id="00000000000000000006" level="6">String</item> <item isNull="true" level="6" />
</value> </entry> <entry> <key class="java.lang.String" isNull="false" id="00000000000000000007" level="7">k3</key> <value class="java.lang.String[]" isNull="false" id="00000000000000000008" level="7"> <item class="java.lang.String" isNull="false" id="00000000000000000009" level="6">1</item> <item class="java.lang.String" isNull="false" id="00000000000000000010" level="6">String2</item> <item class="java.lang.String" isNull="false" id="00000000000000000011" level="6">Strign3</item> <item class="java.lang.String" isNull="false" id="00000000000000000012" level="6">String4</item> </value> </entry> <entry> <key class="java.lang.String" isNull="false" id="00000000000000000013" level="7">k1</key> <value class="java.lang.String" isNull="false" id="00000000000000000014" level="7">Valor1</value> </entry> <entry> <key class="java.lang.String" isNull="false" id="00000000000000000015" level="7">k2</key> <value class="java.lang.String" isNull="false" id="00000000000000000016" level="7">Valor2</value> </entry> </ NombreParmetro > Lista de Lista de Listas: < NombreParmetro class="java.util.ArrayList" isNull="false" id="00000000000000000001" level="8"> <item class="java.lang.String" isNull="false" id="00000000000000000002" level="7">ElementoLista7</item> <item class="java.util.ArrayList" isNull="false" id="00000000000000000003" level="7"> <item class="java.lang.String" isNull="false" id="00000000000000000004" level="6">ElementoLista6</item> <item class="java.util.ArrayList" isNull="false" id="00000000000000000005" level="6"> <item class="java.lang.String" isNull="false" id="00000000000000000006" level="5">ElementoLista5</item> <item class="java.util.ArrayList" isNull="false" id="00000000000000000007" level="5"> <item class="java.lang.String" isNull="false" id="00000000000000000008" level="4">ElementoLista4</item> <item class="java.util.ArrayList" isNull="false" id="00000000000000000009" level="4"> <item class="java.lang.String" isNull="false" id="00000000000000000010" level="3">ElementoLista3</item> <item class="java.util.ArrayList" isNull="false" id="00000000000000000011" level="3"> <item class="java.lang.String" isNull="false" id="00000000000000000012" level="2">ElementoLista2</item> <item class="java.util.ArrayList" isNull="false" id="00000000000000000013" level="2"> <item class="java.lang.String" isNull="false" id="00000000000000000014" level="1">ElementoLista1</item> <item class="java.util.ArrayList" isNull="false" id="00000000000000000015" level="1" /> </item> </item> </item> </item> </item> </item> </ NombreParmetro >
Donde: NombreParmetro: es el nombre del parmetro de salida de la regla. Class: es la clase de ese parmetro. isNull: true si el valor del parmetro es nulo, false en caso contrario. Id: es el identificador del nodo XML, secuencial.
Level: el nivel del nodo XML, empieza de 8. Solo se soportan 8 niveles de anidamiento. Por ejemplo, si se tiene una lista que contiene otra lista que contiene otra lista que contiene otra lista, la primera tendr nivel 8, la 2da 7, la 3ra 6, y la cuarta 5. Si hay ms de 8 niveles de anidamiento, slo viajarn en el xml los primeros 8. En el ejemplo anterior, la primer lista contiene un elemento String y una lista, con la misma estructura que la anterior. En el caso que el valor del parmetro de salida sea una estructura, si es un mapa, cada elemento clave/valor est contenido en la siguiente estructura: <entry> <key class="java.lang.String" isNull="false" id="00000000000000000002" level="7">Clave</key> <value class="java.lang.String" isNull="false" id="00000000000000000003" level="7">Valor</value> </entry> Y en el caso que sea una lista o un arreglo: <item class="ClaseDelElemento" isNull="false" id="00000000000000000002" level="7">Elemento</item>
getXMLElementValue(pXMLRoot, pXMLPath): Devuelve el texto del primer elemento XML dentro de todos los subtags de pXMLRoot que coincida con el path pXMLPath. Este path puede especificar un camino de varios niveles separando los nombres de los tags por / Ej (Mapa): getXMLElementValue (pXMLRoot, nombreParmetro/entry/key); (Lista): getXMLElementValue (pXMLRoot, nombreParmetro/item); (ClaseSimple) getXMLElementValue (pXMLRoot, nombreParmetro);
findXMLChild(pXMLRoot, pNodeName): Devuelve el primer subelemento de un nodo XML con tag llamado pNodeName Ej: findXMLChild(pXMLRoot, nombreParmetro) findXMLChild(pXMLRoot, Key) findXMLChild(pXMLRoot, value)
getXMLAttribute(pXMLNode, pAttributeName): Devuelve el valor de un atributo llamado pAttributeName de un nodo XML Ej: Var xElement = getXMLElement(pXMLRoot, nombreParmetro); getXMLAttribute (xElement , level) getXMLAttribute (xElement, class) getXMLAttribute (xElement, isNull)
getXMLChildText(pXMLRoot, pNodeName): Devuelve el texto contenido en el child de un nodo XML Ej: getXMLChildText (pXMLRoot, nombreParmetro): getXMLChildren(pXMLDocument, pXMLPath): Devuelve todos los elementos correspondientes al path especificado Ej: (Lsita) getXMLChildren (pXMLRoot, nombreParmetro/item): getXMLChildrenTexts(pXMLDocument, pXMLPath): Devuelve el texto de todos los elementos correspondientes al path especificado Ej: (Lsita) getXMLChildrenTexts (pXMLRoot, nombreParmetro/item):
Aplicaciones:
Hasta aqu se ha explicado cmo es la funcin para ejecutar una regla mediante ajax, cmo obtener un elemento XML y su valor, cmo es la estructura XML del resultado de la ejecucin del ajax y ahora, cmo integro estos conocimientos? Qu puedo hacer con ajax? A continuacin se presentan algunos ejemplos de lo que se podra realizar con ajax. Se debe tener en cuenta que las aplicaciones pueden implementar de esta forma la funcionalidad que requieran.
Ejemplo 1: Supongamos un sistema de administracin de pasajes para usuarios: El sistema contendr un proceso de generacin masiva de pasajes, en el cual se indicar el tipo de pasajes a generar (terrestres o areos), el nro. del 1er pasaje a generar, y el nro. del ltimo pasaje a generar. Entonces, el sistema generar la cantidad de pasajes indicadas del tipo indicado, con un nro. secuencial que empezar con el nro. del 1er pasaje hasta el nro. del ltimo. Ej: si se selecciona, tipo de pasaje areo, nro. desde = 134, nro. hasta = 136, el sistema generar 3 pasajes areos: el 134, 135, 136. El Luego, estos pasajes se repartirn entre usuarios, pero, quedemos por ahora con esta idea: generar pasajes. Sera ideal, que, al seleccin el tipo de pasaje, se complete automticamente el campo nro. desde, con el nro. siguiente al ltimo nro. de pasaje de ese tipo. Ej: si el ltimo nro. de pasaje areo generado es 133, sera ideal que cuando elija el tipo de pasaje areo, se autocomplete el nro. desde con 134. Para hacer esto, ser necesario llamar a la ejecucin de un componente mediante ajax, y lgicamente, deber hacerse en el evento onChange del combo que contiene el tipo de pasaje. Primero, necesitamos la regla a llamar, ej: contarPasajes. No interesa para este ejemplo qu hace la regla ni de qu tipo es, slo interesa su nombre, versin, nombre y tipo de los parmetros de entrada y nombre y tipo de los parmetros de salida. Nombre de la regla: contarPasajes. Versin: 1 Descripcin: devolver el nro. mximo del tipo de pasaje indicado. Esta regla podra devolver directamente el mximo ms uno, pero, hacindola de esta forma, es ms probable que pueda ser reutilizada. Parmetros de entrada: pTipoPasaje (String).
Parmetros de salida: pCantidad (Integer). Supongamos que los campos son: Tipo de pasaje (asociado a una tabla, en el momento que se carga la servlet se transforma en combo): < INPUT type="text" class="text_1" name="tipoPasaje" id="tipoPasaje" > Nro desde: <INPUT type="text" class="text_1" name="nroDesde" id="nroDesde" > Nro hasta: < INPUT type="text" class="text_1" name="nroHasta" id="nroHasta" > Llamamos a la funcin que llama el ajax en el onChange de tipoPasaje, y le asignamos como parmetro a s mismo (tipoPasaje): < INPUT type="text" class="text_1" name="tipoPasaje" id="tipoPasaje" onChange=contarPasajes(this) >
function contarPasajes(pEventSource){ /* Esta es la funcin que se ejecutar al finalizar la ejecucin del ajax. pXMLRoot (el nombre puede ser cualquiera), contendr el elemento raz del XML (RESULT), pError contendr un booleano, indicando si hubo o no error, y pParams contendr el arreglo con los parmetros adicionales de esta funcin.*/ var xFunction = function(pXMLRoot, pError, pParams){ // Si no hubo error if(!pError){ /* Recuperamos el tag xml que representa el parmetro de salida de la regla. Podra utilizarse getXMLChildText para recuperar directamente el valor. */ var xElement = findXMLChild(pXMLRoot,pCantidad); /* Podra preguntar si el valor de este element es nulo, para evitar un null: Recordar que los atributos devueltos, siempre son de tipo String.*/ if(getXMLAttribute (xElement, isNull) ==false){ /* Y asignamos el valor del elemento al parmetro de entrada (que ser nroDesde). Como el valor del XML es un String, es necesario hacer la conversin a entero, y le sumamos uno, para que sea el prximo nro. de pasaje a asignar*/ pParams[0].value = parseInt(xElement.nodeValue) +1; } else { pParams[0].value = 1; } } }; //Fin funcin // Obtenemos el valor del tipo de pasaje Var xTipoPasaje = pEventSource.value; // Obtenemos nroDesde var xNroDesde = document.getElementById(nroDesde); // Llamamos al ajax. Los parmetros no indicados de toman como null. executeComponentAjax(contarPasajes, 1, *pTipoPasaje,xTipoPasaje], xFunction, [xNroDesde]);
/*Listo, en este momento el ajax empieza a ejecutarse. Cuando termina, se ejecuta la funcin xFunction. Todo lo que sigue a partir de esta lnea, seguir ejecutndose normalmente (no se congela ni espera a que termine el ajax) */ } Ejemplo2: Muchas veces, resultara til cargar datos en un combo segn el valor de otro combo, dinmicamente. GPA soporta, desde Visio, el filtrado de combos cuando es 1 a 1 (es decir, un combo puede filtrar los datos de un nico combo, y un combo puede ser filtrado por un nico combo). El problema es que no se puede hacer un filtrado mltiplo (que un combo filtre 2 o ms combos, o bien, que un combo sea filtrado por 2 o ms). Al menos, no se puede configurndolo desde Visio, pero s mediante AJAX. Vamos a ver un ejemplo del caso 2 (un combo sea filtrado por otros dos, la idea es explicar cmo se puede llenar un combo con el resultado de un ajax, no explicar la solucin para cada requerimiento particular que pueda surgir, ya la solucin de cada problema depende de la habilidad y lgica del programador):
Supongamos un sistema de compras, con productos catalogados por clase y marca, y un catlogo de proveedores. Cada producto tendr su descripcin, marca, precio estimado, etc, etc. Sera til, poder conocer, para una combinacin de clase de producto y marca, qu proveedores proveen dicho producto. Ej: Se desean comprar Monitores de la marca XXX, y se desea saber, del catlogos de proveedores, qu proveedores proveen dicho producto.
Primero, necesitamos nuestra regla: Nombre de la regla: ProveedoresPorClaseYMarca. Versin: 1 Descripcin: Dado una clase de producto y una marca, retornar la lista de proveedores que trabajen con esa marca y tipo de producto. Parmetros de entrada: pClaseProducto (String). pMarcaProducto (String). Parmetros de salida: pIdProveedores (String[]). // Identificador del proveedor pDsProveedores (String[]). // Nombre del proveedor
Supongamos que los campos son: Clase de producto (asociado a una tabla): < INPUT type="text" class="text_1" name="claseItem" id=" claseItem " > Marca de producto (asociado a una tabla): <INPUT type="text" class="text_1" name="marcaItem" id=marcaItem " > Proveedores (asociado a la regla traerProveedores, y con parmetros asignados desde Visio (esto, para que no sea necesario ejecutar el ajax cuando se consulta el formulario)): < INPUT type="text" class="text_1" name="idProveedor" id="idProveedor " > Llamamos a la funcin que llama el ajax en el onChange de claseItem y marcaItem: <INPUT type="text" class="text_1" name="claseItem" id="claseItem " onChange=actualizarProveedores() > <INPUT type="text" class="text_1" name="marcaItem" id="marcaItem " onChange= actualizarProveedores() >
Function traerProveedores(pEventSource){ /* Esta es la funcin que se ejecutar al finalizar la ejecucin del ajax. pXMLRoot (el nombre puede ser cualquiera), contendr el elemento raz del XML (RESULT), pError contendr un booleano, indicando si hubo o no error, y pParams contendr el arreglo con los parmetros adicionales de esta funcin. En este ejemplo, no usaremos parmetros de entrada de la funcin, aunque se podra hacerlo, normalmente.*/ var actualizarProveedores = function(pXMLRoot, pError){ // Si no hubo error if(!pError){ /* Recuperamos los tag xml que representan los parmetros de salida de la regla. Al ser un arreglo, recuperamos todos los elementos, y para ahorrar trabajo, usamos la funcin getXMLChildrenTexts */ var xIdProveedores = getXMLChildrenTexts(pXMLRoot, pIdProveedores/item); var xDsProveedores = getXMLChildrenTexts(pXMLRoot, pDsProveedores/item); //Buscamos el combo de proveedores: Var xSelect = document.getElementById(idProveedor); //Vaciamos el combo de Proveedores: while (xSelect.options.length > 0){ xSelect.remove(0); } // Le agregamos al combo un elemento vaco: var xOption = document.createElement('option'); xOption.value = ""; xOption.text = ""; xSelect.options[0] = xOption; // Llenamos el combo con los nuevos valores: for (var i=1; i < xIdProveedores.length; i++){ xOption = document.createElement('option'); xOption.value = ""+ xIdProveedores[i]; xOption.text=""+ xDsProveedores[i]; xSelect.options[xSelect.options.length] = xOption; } } }; // Fin funcin // Obtenemos los valores de ambos combos var xClaseItem = document.getElementById(claseItem).value; var xMarcaItem = document.getElementById(marcaItem).value; // Llamamos al ajax. Los parmetros no indicados de toman como null. executeComponentAjax(ProveedoresPorClaseYMarca, 1, *pClaseProducto, xClaseItem, pMarcaProducto, xMarcaItem], xFunction); /*Listo, en este momento el ajax empieza a ejecutarse. Cuando termina, se ejecuta la funcin xFunction. Todo lo que sigue a partir de esta lnea, seguir ejecutndose normalmente (no se congela ni espera a que termine el ajax) */