i
Ejecución de Reglas mediante Ajax
Es posible adaptar el funcionamiento de los formularios digitales modelados en el proceso y extender su funcionalidad mediante la utilización de Ajax para, por ejemplo, obtener datos desde el servidor dinámicamente, validar datos, filtro múltiple de combos, autocompletar datos, actualizar datos dinámicamente, etc.
En Deyel, los “Ajax” se implementan mediante la utilización de reglas y el llamado de las mismas desde el archivo javascript del formulario digital.
Dichos archivos incluyen la función executeComponentAjax.
Esta función recibe los siguientes parámetros:
•{String} pCdComponent: Código de componente a ejecutar
•{String} pCdComponentVersion: Versión del componente a ejecutar
•{Array} pLsComponentINParameters: Valores para los parámetros de entrada de componentes. Es un Array de la forma [InParamName1, InParamValue1, ..., InParamNameN, InParamValueN], donde InParami es el nombre del parámetro de entrada de la regla y lnParamValue es el valor que tomará dicho parámetro. No es necesario que de pasen los parámetros en el orden que están definidos en la regla, ni tampoco que se defina un valor para cada parámetro (los parámetros no indicados en este arreglo, tomarán en la regla en valor por defecto (null)).
•{Function} pCallbackFunction Función que se ejecuta cuando el AJAX ejecutó correctamente. Esta función recibirá tres parámetros: el nodo raíz del resultado de la ejecución, un boolean para indicar si hubo errores o no, y pLsCallbackFunctionParameters.
•{Array} pLsCallbackFunctionParameters: Valores para pasar como parámetro a la función pCallbackFunction.
•{Boolean} pShowWaitMessage: Indica si se mostrará un mensaje de espera mientras se realiza la petición 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
Ejecución de la regla:
executeComponentAjax(pCdComponent, pCdVersion, pLsComponentINParameters, pCallbackFunction, pLsCallbackFunctionParameters, pShowWaitMessage, pDsWaitMessage)
Ejemplo asignación de parámetros:
var xFunction = function(pXMLRoot,pError,pParams){
// Código a ejecutar cuando termine la ejecución del Ajax;
}
executeComponentAjax(“NombreDeLaRegla”, ”Versión”, [“nombreParámetro1”,”valorParámetro1”,” nombreParámetro2”, “valorParámetro2”], xFunction, [“valorParámetro1”, “valorParámetro2”], false, null);
No es necesario que la regla posea parámetros de entrada ni de salida, ni tampoco es obligatorio llamar a la regla con parámetros de entrada asignados (pLsComponentINParameters puede ser null).
Una vez que el componente ejecutó, y devolvió el resultado de la ejecución, se debería procesar el resultado. En este momento se ejecuta la función asignada como parámetro.
En esta función deberían estar todas las acciones que se desean hacer luego de que el ajax ejecutó, por ejemplo, asignar el resultado de un parámetro de la regla a un campo, mostrar algún mensaje, ejecutar alguna otra función, etc.
Se debe tener en cuenta que la ejecución de ajax es asincrónica, por lo tanto, mientras el ajax se está ejecutando, no se bloqueará la ejecución de javascript.
El resultado de la ejecución del ajax será una estructura XML. A continuación, se describirá esta estructura, y luego, cómo recorrerla u obtener los valores que se deseen.
Estructura XML con el resultado de la ejecución:
Salida de la servlet AJAX:
<?xml version="1.0" encoding="ISO-8859-1"?>
<response>
<RESULT success="true/false" rule="NombreDeLaRegla-Versión">
.
.
.
</RESULT>
</response>
Donde “success”, es “true”, si la regla ejecutó correctamente, y “false” si ocurrió algún error durante la ejecución de la misma.
El nodo resultado que se envía como parámetro a la función (que se ejecuta cuando el ajax ejecuta correctamente) es el resultado de la ejecución de la regla, devuelto en esta estructura xml, a partir del tag “RESULT”.
Dentro del tag “RESULT” se encontrarán, dependiendo de la clase del parámetro de salida, las siguientes estructuras que contendrán el valor de los parámetros 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
•Arreglos
Se soportan hasta ocho niveles de anidamiento de estructuras
•String:
<NombreParámetro class="java.lang.String" isNull="false" id="00000000000000000001" level="8">String</ NombreParámetro >
•Integer:
< NombreParámetro class="java.lang.Integer" isNull="false" id="00000000000000000001" level="8">5</ NombreParámetro >
•Double:
< NombreParámetro class="java.lang.Double" isNull="false" id="00000000000000000001" level="8">0.0</ NombreParámetro >
•BigDecimal:
< NombreParámetro class="java.math.BigDecimal" isNull="false" id="00000000000000000001" level="8">0</ NombreParámetro >
•java.sql.Date:
< NombreParámetro class="java.sql.Date" isNull="false" id="00000000000000000001" level="8">2012-06-01</ NombreParámetro >
•java.sql.Timestamp:
< NombreParámetro class="java.sql.Timestamp" isNull="false" id="00000000000000000001" level="8">2012-06-01 00:00:00.0</NombreParámetro >
•Boolean:
< NombreParámetro class="java.lang.Boolean" isNull="false" id="00000000000000000001" level="8">false</ NombreParámetro >
•Null:
< NombreParámetro isNull="true" level="8" />
Para estructuras:
•Arreglo
< NombreParámetro 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>
</ NombreParámetro >
•Lista
< NombreParámetro 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" />
</ NombreParámetro >
•Mapa
< NombreParámetro 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>
</ NombreParámetro >
•Mapa con otras Estructuras
< NombreParámetro 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>
</ NombreParámetro >
•Lista de Lista de Listas
< NombreParámetro 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>
</ NombreParámetro >
Donde:
•NombreParámetro: es el nombre del parámetro de salida de la regla.
•Class: es la clase de ese parámetro.
•isNull: true si el valor del parámetro es nulo, false en caso contrario.
•Id: es el identificador del nodo XML, secuencial.
•Level: el nivel del nodo XML, comienza con nivel ocho. Solo se soportan ocho niveles de anidamiento. Por ejemplo, se tiene una lista que contiene 3 listas anidadas sucesivamente, la primera tendrá nivel 8, la segunda 7, la tercera 6, y la cuarta 5. Si hay más de ocho niveles de anidamiento, sólo viajarán en el xml los primeros ocho.
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 parámetro de salida sea una estructura, como 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>
Métodos para obtener los valores del XML:
Funciones primitivas:
No se describirán las funciones primitivas para manipular datos XML, solo se presentarán algunos ejemplos:
xElemntoXML.firstChild.nodeValue // Devuelve el valor del 1er hijo de la raíz
xElemntoXML.childNodes // Devuelve el arreglo de hijos
xElemntoXML.attributes[i].value // Devuelve el valor del atributo de la posición i de un
//elemento xml
xElemntoXML.getElementsByTagName(“tagName”) // Obtiene los elementos con el
//tagName indicado.
Etc.
Funciones desarrolladas para facilitar el acceso a elementos XML:
•getXMLElement(pXMLRoot, pXMLPath): Devuelve el primer elemento XML dentro de todos los subtags de “pXMLRoot” que coincida con el “path pXMLPath”. Dicho “path” puede especificar un camino de varios niveles separando los nombres de los tags por “/”.
Ejemplo Mapa: getXMLElement(pXMLRoot, “NombreParámetro/entry/key”);
Ejemplo Lista: getXMLElement(pXMLRoot, “NombreParámetro/item”);
Ejemplo ClaseSimple: getXMLElement(pXMLRoot, “NombreParámetro”);
•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 “/”.
Ejemplo Mapa: getXMLElementValue (pXMLRoot, “nombreParámetro/entry/key”);
Ejemplo Lista: getXMLElementValue (pXMLRoot, “nombreParámetro/item”);
Ejemplo ClaseSimple: getXMLElementValue (pXMLRoot, “nombreParámetro”);
•findXMLChild(pXMLRoot, pNodeName): Devuelve el primer subelemento de un nodo XML con tag llamado pNodeName.
Ejemplo Mapa: findXMLChild(pXMLRoot, “Key”);
Ejemplo Lista: findXMLChild(pXMLRoot, “value”);
Ejemplo ClaseSimple: findXMLChild(pXMLRoot, “nombreParámetro”);
•getXMLAttribute(pXMLNode, pAttributeName): Devuelve el valor de un atributo llamado pAttributeName de un nodo XML.
Ejemplo:
var xElement = getXMLElement(pXMLRoot, “nombreParámetro”);
getXMLAttribute (xElement , “level”)
getXMLAttribute (xElement, “class”)
getXMLAttribute (xElement, “isNull”)
•getXMLChildText(pXMLRoot, pNodeName): Devuelve el texto contenido en el child de un nodo XML.
Ejemplo: getXMLChildText (pXMLRoot, “nombreParámetro”);
•getXMLChildren(pXMLDocument, pXMLPath): Devuelve todos los elementos correspondientes al path especificado.
Ejemplo Lista: getXMLChildren (pXMLRoot, “nombreParámetro/item”);
•getXMLChildrenTexts(pXMLDocument, pXMLPath): Devuelve el texto de todos los elementos correspondientes al path especificado
Ejemplo Lista: getXMLChildrenTexts (pXMLRoot, “nombreParámetro/item”):
Aplicaciones:
Hasta aquí se ha explicado cómo es la función para ejecutar una regla mediante AJAX, cómo obtener un elemento XML y su valor, cómo es la estructura XML del resultado de la ejecución del AJAX. Ahora se presentarán algunas aplicaciones de lo que se puede lograr con AJAX.
A continuación se presentan algunos ejemplos de lo que se podría 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 administración de pasajes para usuarios. El sistema contendrá un proceso de generación masiva de pasajes, en el cual se indicará el tipo de pasajes a generar (terrestres o aéreos), el número del primer pasaje a generar y del último. Entonces, el sistema generará la cantidad de pasajes indicados del tipo indicado, con un número secuencial que empezará con el número del primer pasaje hasta el último. Por ejemplo, si se selecciona tipo de pasaje aéreo, número desde = 134, número hasta = 136, el sistema generará tres pasajes aéreos: el 134, 135, 136. Luego, estos pasajes se repartirán entre usuarios, pero quedemos por ahora con esta idea: generar pasajes.
Sería ideal que al seleccionar el tipo de pasaje, se complete automáticamente el campo número desde, con el número siguiente al último número de pasaje de ese tipo. Por ejemplo, si el último número de pasaje aéreo generado es 133, sería ideal que cuando elija el tipo de pasaje aéreo, se autocomplete el número desde con el valor 134. Para hacer esto, será necesario llamar a la ejecución de un componente mediante AJAX, y lógicamente, deberá hacerse en el evento “onChange” del combo que contiene el tipo de pasaje.
Al comenzar, necesitamos la regla a llamar, como por ejemplo, “contarPasajes”.
No es de interés para este ejemplo qué hace la regla ni de qué tipo es, sólo será necesario su nombre, versión, nombre y tipo de los parámetros de entrada; y nombre y tipo de los parámetros de salida.
Nombre de la regla: contarPasajes.
Versión: 1.
Descripción: devolverá el número máximo del tipo de pasaje indicado. Esta regla podría devolver directamente el máximo más uno, pero haciéndola de esta forma, es más probable que pueda ser reutilizada.
Parámetros de entrada: pTipoPasaje (String).
Parámetros 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" >
Número desde:
<INPUT type="text" class="text_1" name="nroDesde" id="nroDesde" >
Número hasta:
< INPUT type="text" class="text_1" name="nroHasta" id="nroHasta" >
Llamamos a la función que llama el AJAX en el “onChange” de la regla tipoPasaje, y le asignamos como parámetro a sí mismo (tipoPasaje):
<INPUT type="text" class="text_1" name="tipoPasaje" id="tipoPasaje" onChange=”contarPasajes(this)” >
En el archivo “modifierScript.js”, del formulario, definimos la función:
function contarPasajes(pEventSource){
/* Esta es la función que se ejecutará al finalizar la ejecución del ajax. pXMLRoot (el nombre puede ser cualquiera), contendrá el elemento raíz del XML (RESULT), pError contendrá un booleano, indicando si hubo o no error, y pParams contendrá el arreglo con los parámetros adicionales de esta función.*/
var xFunction = function(pXMLRoot, pError, pParams){
// Si no hubo error
if(!pError){
/* Recuperamos el tag xml que representa el parámetro de salida de la regla.
Podría utilizarse getXMLChildText para recuperar directamente el valor.
*/
var xElement = findXMLChild(pXMLRoot,”pCantidad”);
/* Podría 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 parámetro de entrada (que será nroDesde). Como el valor del XML es un String, es necesario hacer la conversión a entero, y le sumamos uno, para que sea el próximo nro. de pasaje a asignar*/
pParams[0].value = parseInt(xElement.nodeValue) +1;
} else {
pParams[0].value = 1;
}
}
}; //Fin función
// Obtenemos el valor del tipo de pasaje
Var xTipoPasaje = pEventSource.value;
// Obtenemos nroDesde
var xNroDesde = document.getElementById(“nroDesde”);
// Llamamos al ajax. Los parámetros no indicados se toman como null.
executeComponentAjax(“contarPasajes”, ”1”, [“pTipoPasaje”,xTipoPasaje], xFunction, [xNroDesde]);
/*Listo, en este momento el ajax empieza a ejecutarse. Cuando termina, se ejecuta la función xFunction.
Todo lo que sigue a partir de esta línea, seguirá ejecutándose normalmente (no se congela ni espera a que termine el ajax)
*/
}
Ejemplo2:
Muchas veces, resultaría útil cargar datos en un combo según el valor de otro, dinámicamente. Deyel 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 múltiplo (que un combo filtre dos o más combos, o bien, que un combo sea filtrado por dos o más). Al menos, no se puede configurándolo desde Visio, pero sí mediante AJAX.
Vamos a ver un ejemplo del segundo caso evaluado anteriormente, que un combo sea filtrado por otros dos. La idea es explicar cómo se puede llenar un combo con el resultado de un AJAX (no se explicará la solución para cada requerimiento particular que pueda surgir, ya que la solución de cada problema depende de la habilidad y lógica del programador):
Supongamos un sistema de compras, con productos catalogados por clase y marca, y un catálogo de proveedores. Cada producto tendrá su descripción, marca, precio estimado, etc. Sería útil poder conocer, para una combinación de clase de producto y marca, qué proveedores brindan dicho producto.
Por ejemplo, se desean comprar monitores de la marca “XXX”, y se pretende saber, del catálogo de proveedores, cuáles de estos proveen dicho producto.
Primero, necesitamos la regla encargada de conseguir los datos necesarios:
Nombre de la regla: ProveedoresPorClaseYMarca.
Versión: 1.
Descripción: dado una clase de producto y una marca, retornará la lista de proveedores que trabajen con esa marca y tipo de producto.
Parámetros de entrada: pClaseProducto (String).
pMarcaProducto (String).
Parámetros 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 parámetros 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 función 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 función que se ejecutará al finalizar la ejecución del AJAX. “pXMLRoot” (el nombre puede ser cualquiera), contendrá el elemento raíz del XML (RESULT), pError contendrá un booleano, indicando si hubo o no error, y pParams contendrá el arreglo con los parámetros adicionales de esta función. En este ejemplo, no usaremos parámetros de entrada de la función, aunque se podría hacerlo, normalmente.*/
var actualizarProveedores = function(pXMLRoot, pError){
// Si no hubo error
if(!pError){
/* Recuperamos los tag xml que representan los parámetros de salida de la regla. Al ser un arreglo, recuperamos todos los elementos, y para ahorrar trabajo, usamos la función 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 vacío:
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 función
// Obtenemos los valores de ambos combos
var xClaseItem = document.getElementById(“claseItem”).value;
var xMarcaItem = document.getElementById(“marcaItem”).value;
// Llamamos al ajax. Los parámetros no indicados se 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 función xFunction.
Todo lo que sigue a partir de esta línea, seguirá ejecutándose normalmente (no se congela ni espera a que termine el ajax)
*/
}
Algunos comentarios y consideraciones especiales:
Por si fuera necesario cargar un combo desde AJAX, Optaris desarrollo un tipo de dato “Mapa”, y métodos especiales para llenar un mapa con el resultado de la ejecución de AJAX, y métodos para completar un combo con un mapa. El detalle del mismo se ve en este documento, en el apartado “Uso de mapas en javascript”.
// Instanciamos un nuevo mapa
var xMapa = new Map();
// Esta función carga el mapa con el resultado de la ejecución de un ajax. Recibe como parámetros, la raíz XML, y el nombre de 2 parámetros de salida, el 1ro para usar como clave del combo, y el otro como descripción
xMapa.loadFromAjax(pXMLRoot, " pIdProveedores", " pDsProveedores");
/* xSelect será el combo HTML a llenar, el 2 parámetros, es para borrar o no el contenido actual del combo, el siguiente, es el valor seleccionado por defecto (como valor, no posición), y el último, y si se quiere que esté la opción vacía para elegir en el combo*/
xMapa.fillCombo(xSelect,true,null,false);
Cuando se ejecuta una regla mediante AJAX, se intenta convertir el tipo de dato enviado (String) al tipo de dato indicado en el parámetro de entrada de la regla. Para datos simples, la conversión es posible. Para arreglos, listas (no existen en javaScript), mapas (tampoco existen) y demás, no.
Recordar que AJAX se ejecuta en el servidor, y genera tráfico de red, y procesamiento. Muchas veces se puede optimizar el uso de AJAX. Por ejemplo, en el primer ejemplo se vio la ejecución de una regla en el “onChange” de un combo. Sería más optimo, ejecutar un AJAX en el “onLoad” de la página, que llame a una regla que devuelva las dos cantidades máximas de pasajes para cada tipo, y almacenar ese valor en variables globales (o en un mapa), y, en el “onChange” del combo, consultar las variables globales, y no ejecutar el Ajax (todo esto pensando en el ejemplo número 1).
Se puede usar AJAX para validar datos dinámicamente. Pero, cabe recordar que mientras se ejecuta el AJAX, la página sigue activa. Entonces, sería necesario, cuando se ejecute el Ajax, bloquear los botones “submit”, y cuando termine de ejecutar, desbloquearlos.
No es necesario definir la función que se ejecuta al retorna el Ajax dentro de la función que ejecuta el Ajax. Podría ser una función aparte.