Professional Documents
Culture Documents
B
ConsistGPA Pgina 1 de 37
ConsistGPA
Pgina 2 de 37
Descripcin
En el presente documento se detallan algunas consideraciones tiles para el modelado de formularios.
1) El Formulario que vamos a definir es uno de ejemplo con la finalidad de poder mostrar las recomendaciones.
como se ve, este Formulario cuenta con una serie de campos simples como ser el Id, Apellido, Nombre, etc. Y un campo compuesto Prstamo con 4 campos hijo (fecha, monto, cantCuota, montoCuota).
ConsistGPA
Pgina 3 de 37
Como se muestra en la figura anterior, los campos y sus descripciones se ubican uno por fila, una debajo del otro. Esto es como lo genera el Generador De Formularios originalmente sin la utilizacin de html bsico. Ahora vamos a ver como se puede adaptar el diseo de este Formulario adecundolo a sus necesidades.
3) Ubicar el Formulario creado por ConsistGPA para su posterior modificacin. Cuando se define un nuevo formulario se crea una carpeta dentro del contexto de ConsistGPA. Dicha carpeta tendr por nombre el cdigo que se le dio al Formulario al crearlo y en esta se almacenan las pginas por defecto que se mostraran en la aplicacin (Ver detalle en el manual de usuario). En el ejemplo, el cdigo del Formulario definido es AFM con lo cual, por lo dicho dicho anteriormente, se creo una carpeta con el mismo nombre que contiene los siguientes archivos por defecto. La ubicacin de esta carpeta se encuentra dentro del contexto de ConsistGPA en el Servidor de aplicacin que se est solucionando. En caso de no tener r permiso de acceso por la red a dicha carpeta del servidor se puede realizar el export del formulario desde GPA para modificarlo localmente y luego volver a importarlo.
ConsistGPA
Pgina 4 de 37
A continuacin vamos a modificar el archivo archivo SLGenericDocumentBasic que contiene los datos del Formulario que se defini para el ejemplo. Para lograr dicha finalidad abriremos al archivo con un editor de HTML. Por ejemplo DreamWeaver.
En la imagen anterior se muestra el HTML por defecto, lo que vamos a realizar es la adaptacin de los campos segn la disposicin que necesitemos en nuestro HTML final. Para ello agregaremos una fila al principio del HTML, luego insertamos, en la fila agregada, una tabla con las siguientes caractersticas: Filas=2, Columnas=10 y Ancho=100%. Se redistribuyen los campos para lograr una apariencia en donde se coloque la descripcin descripcin del campo en una lnea y en la lnea de abajo el campo propiamente dicho. O sea que queda una fila con etiquetas del campo y la otra fila con los campos editables. Para tener un control ms acotado del diseo dado que se trabaja por porcentajes se recomienda definir tablas con los porcentajes mencionados solo con 2 filas por tabla, trabajando as una tabla para
ConsistGPA
Pgina 5 de 37
cada fila de campos. El estilo default de la aplicacin contempla class para los inputs para corresponderse con los porcentajes de la siguiente ente forma: Al tener una celda con 10 % esto soporta solo un campo input de estilo class="text_1", En caso de tener 20 caracteres debera ser de 20 % y el class con text_2, Si es de 50 caracteres el porcentaje de la columna es 50 % y el class en text_5, y as sucesivamente. Dentro del input de cada campo existen atributos como id y name que NO se deben modificar. A cada celda de la tabla recientemente definida le pondremos en el tag TD un width=10% para que mantenga un ancho fijo y tambin pondremos los atributos atributos class y valign como muestra el ejemplo a continuacin. Ej: <td width="10%" class="fuenteCampo" valign="top"> </td>
Esta operacin la realizaremos tantas veces como filas necesitemos tener en el en el formulario final. Para el ejemplo se realizo 4 veces.
Otra posibilidad es definir la tabla con 5 columnas con un ancho de celda de 20% pero ello queda sujeto a la cantidad de campos del Formulario y su longitud.
Hay que hacer la salvedad de que los campos del Formulario tengan una longitud que que supere al 10% del ancho asignado. Cuando ocurra ello se deber realizar un Merge Cells para obtener mas espacio. Este merge se realiza siempre sobre la segunda lnea de la tabla para no generar desplazamientos. En el ejemplo que utilizamos el campo Apellido Apellido tiene una longitud de 30 caracteres por lo que necesitaremos utilizar mas de una celda para su representacin (cada celda que se define con un ancho de 10% permite el ingreso como mximo de 10 caracteres) con lo cual necesitaremos hacer un Merge Cells de 3 celdas.
ConsistGPA
Pgina 6 de 37
Ej:
Una vez realizado esto para todos los campos del Formulario ya estar el Formulario de acuerdo a los requisitos de visualizacin siguientes.
Al ver la imagen anterior se detecta que el tamao del RichText no se puede ajustar desde el Formulario SLGenericDocumentBasic. En caso que deseramos modificar el tamao de este debemos modificar el archivo RichTextFieldComponent que se encuentra ubicado dentro de la carpeta del Formulario en una subcarpeta llamada Components. Abrir el archivo con algn editor de HTML, modificar la variable width y height al tamao deseado de ancho y alto respectivamente.
ConsistGPA
Pgina 7 de 37
Con esto concluimos la serie de paso recomendados para la modificacin de Formularios Formularios quedando el diseo final del Formulario de ejemplo de la siguiente manera.
ConsistGPA
Pgina 8 de 37
Cuando se define en el formulario un campo del tipo Date se puede agregar la funcionalidad para cargar dicha fecha con la ayuda yuda de un calendario emergente. Para poder disponer de dicha funcionalidad se debe primeramente modificar en el INPUT del campo en cuestin el valor de la propiedad class=text_fecha.
Una vez realizada esta operacin se debe incorporar junto al campo la imagen del calendario. Esto se realiza de la siguiente forma:
<IMG width="15" height="15" style="cursor:hand" onClick="javascript:NewCal(fecha fecha,document.getElementById('TIMESTAMP_ENTRY_MASKHidden' ,document.getElementById('TIMESTAMP_ENTRY_MASKHidden' ).value)" src="calendar.gif" border="0" name="date1" id="imageMain" >
Donde el texto en verde representa la ID del campo de tipo Date, por lo que hay que reemplazarlo por la ID del campo al que le queremos eremos agregar el icono, el resto de la informacin es constante para todos los calendarios que se deseen agregar.
Como se ve en la imagen, a la derecha del campo Fecha (que es de tipo Date) aparece un icono, y cuando se hace click sobre el mismo aparece apa la ventana emergente de seleccin de fecha.
ConsistGPA
Pgina 9 de 37
Comentarios sobre la interfaz del ejemplo: Todos los iterativos estn, por defecto, colapsados, y se muestra siempre el ltimo iterativo de la lista. Este criterio o puede cambiar en base a las necesidades del usuario. Este efecto se logra llamando a la siguiente funcin en los onLoads correspondientes (modifyCreate, modifyUpdate, modifyShow), que tambin asigna el comportamiento a los botones colapsables dentro de los iterativos:
function setCollapsableButtons(){ processIterative("fkModificaA",setCollapsable); processIterative("fkModificadoPor",setCollapsable); var xFunction = function(pIterative){ if(findChildById(pIterative,"fkModificaA/dsClasificacion").value == 'T'){ pIterative.style.display = ""; } else { pIterative.style.display = "none"; } }; setIMGCollapsableForIterative( document.getElementById("collapsableIterativefkModificaA"), "fkModificaA", document.getElementById("collapsableIterativefkModificaA"), "./themes/default/ES/imagenes/mas.png", "./themes/default/ES/imagenes/menos.png", "Mas datos", "Menos datos", true, "ultimo"); setIMGCollapsableForIterative( document.getElementById("collapsableIterativelsFuentes"), "lsFuentes", "./themes/default/ES/imagenes/mas.png", es/default/ES/imagenes/mas.png", "./themes/default/ES/imagenes/menos.png", "Mas datos", "Menos datos", true, "ultimo"); setIMGCollapsableForIterative(document.getElementById( "collapsableIterativelsProcesos"), "lsProcesos", "./themes/default/ES/imagenes/ "./themes/default/ES/imagenes/mas.png", "./themes/default/ES/imagenes/menos.png", "Mas datos", "Menos datos", true, "ultimo"); setIMGCollapsableForIterative(document.getElementById("collapsablefkModificadoPor "), "fkModificadoPor", "./themes/default/ES/imagenes/mas.png", "./themes/default/ES/imagenes/menos.png", /default/ES/imagenes/menos.png", "Mas datos", "Menos datos", true, "ultimo"); } function setCollapsable(pIterative){ setIMGAsCollapsable(findChildById(pIterative,"collapsableButton"), pIterative.id, "collapsablePanel", "./themes/default/ES/imagenes/mas.png", "./themes/default/ES/imagenes/menos.png", "Mas datos", "Menos datos", true, function() {
ConsistGPA
Pgina 10 de 37
El botn de despliegue del iterativo deber estar a la izquierda del ttulo, y a la derecha, el botn de agregar una ocurrencia del iterativo. Los botones de despliegue de datos adicionales de cada ocurrencia del iterativo debe estar a la derecha de esa ocurrencia, en la primera lnea, deparados a una distancia de 5% de la tabla principal, y los botones de eliminar 5% de distancia de la a parte izquierda de la tabla principal. No hacer una tabla con un td de 5%, uno de 90% y otro de 5%, y dentro del td de 90% poner otra tabla con los imputs del iterativo, ya que de esta forma ya no se corresponderan los porcentajes con los tamaos de los campos. Ejemplo: No Hacer:
<TABLE width = 100% id=nombreIterativo style=display:none cellpading=0.> <TR> <TD width=5%> </TD> <TD width=90%> <TABLE width = 100%> <!-< Esta tabla tiene en realidad un ancho del 90% de la tabla principal--> <TD width=20%> </TD> %> <!entonces, <! entonces, estos TD tienen en realidad un 18% del ancho de la tabla principal, y un input de clase text_2, no entra.--> entra. <TD width=20%> </TD> width=20%> </ <TD width=20%> </TD> <TD width=20%> </TD> <TD width=20%> </TD> </TABLE> </TD> <TD width=5%> </TD> </TR> </TABLE>
Si se presiona el botn + que est en el ttulo del iterativo, ste se despliega y muestra el resto de las ocurrencias del iterativo. Las ocurrencias van a aparecer con colores alternados para poder distinguirlas, y se resaltar con otro color la ocurrencia del iterativo sobre la cual est el cursor. Se mostrar el cono de la flecha (au (auto), salvo que si al hacer click sobre la ocurrencia se realice alguna accin. Esto se logra aplicando la siguientes funcines en los onLoads correspondientes:
function setFormatToIterative(pIterativeName,pLsRows,pCursorStyle){ var xFila = "par"; var xFunction unction = function(pIterative){ if(xFila == "par"){ for(var i=0;i<pLsRows.length; i++){ var xRow = findChildById(pIterative,pLsRows[i]); xRow.setAttribute("class","tablaFilaPar"); if(pCursorStyle){ xRow.style.cursor = pCursorStyle; } } xFila = "impar"; } else { for(var i=0;i<pLsRows.length; i++){ var xRow = findChildById(pIterative,pLsRows[i]); xRow.setAttribute("class","tablaFilaImpar"); if(pCursorStyle){ xRow.style.cursor = pCursorStyle; } } xFila = "par"; } } processIterative(pIterativeName,xFunction) }
ConsistGPA
Pgina 11 de 37
En los iterativos con un botn de ms datos, se mantiene el cono de la mano del cursor, y al hacer c click sobre cualquier parte del la ocurrencia (menos en los inputs), se desplegarn los datos adicionales. Para lograr esto, se agreg una funcin que llame al onclick() del botn, pero si se presiona el botn, sta funcin tambin se llama, por lo que hubo que contemplar si el botn ya fue presionado (sin se llamaba al onclick 2 veces, una por presionar el botn, y otra por presionar la fila de la tabla, y los datos se mostraban y ocultabas simultneamente). Esto se solucion de la siguiente manera: Funcin n asignada antes de ejecutar el ocultamiento/desplegamiento de los datos adicionales, mediante el mtodo setIMGAsCollapsable, marcada con azul:
function setCollapsable(pIterative){ setIMGAsCollapsable(findChildById(pIterative,"collapsableButton"), pItera pIterative.id, "collapsablePanel", "./themes/default/ES/imagenes/mas.png", "./themes/default/ES/imagenes/menos.png", "Mas datos", "Menos datos", true, function(){ findChildById(pIterative,"collapsableButton").setAttribute("recentClicked","true" ); setTimeout(function(){ findChildById(pIterative,"collapsableButton").setAttribute("recentClicked","false "); },100); }); }
Funcin que se llama en el onclick de la fila de la tabla(se debe asignar a cada fila del iterativo, en caso de haber ms de una):
function clickCollapsable(pEventSource, pCollapsableId){ var xParent = pEventSource.parentNode; var xButton = findChildById(xParent,pCollapsableId); if(xButton.getAttribute("recentClicked") != "true"){ xButton.onclick(); } }
Tener en cuenta de llamar a la funcin de formateo del iterativo, al agregar o eliminar ocurrencias de ese iterativo, para aplicar el formato a las nuevas ocurrencias agregadas, y, si el iterativo tiene dentro botones colapsables, hay que llamar a la funci funcin n que le aplica el comportamiento a ese botn. Estas funciones se agregan sobre los botones en el HTML. Ejemplo: Agregar:
<input value="Nuevo Elemento" type="button" class="botonadds" onClick="cloneMultipleNode(consist_findElement ('fkModificaA'), consist_findElement consist_findElement ('tablePlacefkModificaA'));setFormatToIterative('fkModificaA',['visiblePanel','collapsab lePanel']);processIterative('fkModificaA',setCollapsable);" name="button" id="button" >
Eliminar:
<input value="Eliminar Elemento" type="button" class="b class="botondels" onClick="deleteMultipleNode(consist_findElement ('fkModificaA'), this.parentNode.parentNode.parentNode);setFormatToIterative('fkModificaA',['visiblePanel ','collapsablePanel']);" name="button" id="button" >
<input value="Guardar e Imprimir" type="submit" class="botonNormalLargo" onMouseOut="setColorButtonMouseOut(this);" name="botonGuardar" onMouseOver="setColorButtonMouseOver(this);" ButtonMouseOver(this);" id="botonGuardar" onclick="setPrintAfterPartialSave('true') onclick="setPrintAfterPartialSave('true');"> </TD> setPrintAfterPartialSave es una funcin definida en el ambiente de GPA, ubicada en la carpeta de script/funcionesComunes.js
xCheckbox.checked = false; } }
function enableCheckBox(pCheck,pCdActivity){ xCdActivity = getCdActivity(); if(xCdActivity == pCdActivity){ document.getElementById(pCheck).disabled=false; } } function disableCheckBox(pCheck,pCdActivity){ CheckBox(pCheck,pCdActivity){ xCdActivity = getCdActivity(); if(xCdActivity == pCdActivity){ dActivity){ document.getElementById(pCheck).disabled=true; document.getElementById(pCheck).disabled= } }
<DIV id="panelTAB_3" > Datos para mostrar al presionar tab3 </DIV> Imagen de los TABS (95 px largo X 20 px alto):
AGREGAR UN BOTON CON LINK PARA EJECUTAR UNA ACTIVIDAD DE OTRO PROCESO CONOCIENDO EL NRO DE CASO.
Para realizar esto se puede previamente crear el caso de otro proceso por executeComponent va js o por una actividad automtica desde el proceso. <TD width="70%" > <INPUT type="text" class="text_3" name="casoReasignado" id="casoReasignado" > ConsistGPA Pgina 15 de 37
<span id="execCaseBTN"><IMG width="15" height="15" style="cursor:pointer" onclick="executeCase();" src="taskPlay.gif" border="0" alt="Ejecutar caso" id="imageMain" ></span> </TD> En modifierScript.js function executeCase(){ var xURL = "SLPlayActivityDispatcher?nuSecHidden="+document.getElementById('nuSecHidden').value; xURL += "&nuExpedienteHidden="+document.getElementById('casoReasignadoHidden').value; window.location = xURL; }
AGREGAR UN BOTON QUE PER PERMITE INICIAR UN CASO DE OTRO PROCESO Y EJECUTAR LA ACTIVIDAD INICIAL DEL MISMO.
El botn del formulario del proceso principal debe tener en el onclick la llamada a la funcin del ejemplo SISCreateCase1 <INPUT value="Notas" type="button" class="botonConIcono" onMouseOut="setColorButtonMouseOut(this);" name="button" onMouseOver="setColorButtonMouseOver(this);" id="botonNotas" ; onClick="SISCreateCase1(this);">
function SISCreateCase1() { var xParams = new Array(); xParams[0] = "pCdSubject"; xParams[1] = "8001" xParams[2] = "pCdUser"; xParams[3] = this.parent.document.getElementById('body1').getAttribute('user'); executeComponentAjax("SISCreateCase1", "1", xParams, SISCreateCaseResult, null); } function SISCreateCaseResult(pNodeResult, ult(pNodeResult, pError){ if (pError){ alert("Error al Iniciar el proceso de Notas de Instruccin (componente SISCreateCase1)."+pError); } else { var xNuNewCase =(getXMLChildText(pNodeResult, "createCaseResult")); alert("El Proceso de Notas de de Instruccin se inici exitosamente. Nro. Caso " + xNuNewCase ); executeCase(xNuNewCase); } } ConsistGPA Pgina 16 de 37
function executeCase(pNuNewCase){ var xURL = "SLPlayActivityDispatcher?nuSecHidden="+document.getElementById('nuSecHidden').value; xURL += "&nuExpedienteHidden="+pNuNewCase; Hidden="+pNuNewCase; window.location = xURL; }
CARGAR VALORES POR DEFAULT DESDE REGLAS EN LOS CAMPOS DEL FORMULARIO.
Se puede configurar desde la ejecucin de una actividad una regla de negocio modelada, se pueden enviar parmetros a la regla de ejecucin. n. Los parmetros pueden ser constantes o campos del formulario. Ejemplo: En la ejecucin de la actividad asignar como valor por defecto lo siguiente: |EXECUTE_RULE(GAFPGetAgentAmount,1,CHOFER)| Esta regla es el siguiente select a una tabla auxiliar: select elect tp_agent, qt_amount from L065 where tp_agent = ?ptpAgent Lee el campo cantidad de la tabla L065 para el tipo de agente = CHOFER En el campo se carga la cantidad recuperada.
onclick="window.location='SLProcessConsultaMSel?nuSecHidden='+document.ge tElementById('nuSecHidden').value+'&cdProcessInit=800&cdVersionInit=2';"
En este ejemplo se resaltan los valores a reemplazar. Estos valores son el nmero de proceso y la versin del proceso. Ejemplo del agregado del botn para abrir el formulario DP1
<input value="Avanzada." type="button" class="botonConIconoArriba" onMouseOut="setColorButtonMouseOut(this);" Out="setColorButtonMouseOut(this);" name="button2" onMouseOver="setColorButtonMouseOver(this);" id="button22" onClick="window.location='SLGenericDocumentSearch?nuSecHidden='+document. getElementById('nuSecHidden').value+'&cdDocumentNameHidden=DP1';" >
Consultar un formulario:
onclick="window.location='SLGenericDocumentSearch?nuSecHidden='+document. getElementById('nuSecHidden').value+'&cdDocumentNameHidden=NNN;"
En este ejemplo se resalta el valor a reemplazar que corresponde al cdigo del formulario. Como se puede consultar ultar en la url del location se concatena en la llamada el id de la sesin recuperndolo del nuSecHidden del formulario. Ejemplo del agregado del botn para iniciar el proceso 7302 versin 2
ConsistGPA
Pgina 18 de 37
<input value="Proceso" type="button" class="botonConIconoArriba" class="botonConIconoArriba" onMouseOut="setColorButtonMouseOut(this);" name="button2" onMouseOver="setColorButtonMouseOver(this);" id="button23" onclick="window.location='SLProcessConsultaMSel?nuSecHidden='+document.ge tElementById('nuSecHidden').value+'&cdProcessInit=7302&cdVersionInit=1';" tElementById('nuSecHidden').value+'&cdProcessInit=7302&cdVersionInit=1';" >
Para agregar estos botones, hay que definir en el HTML un tag IMG como el siguiente: <IMG id="collapsableButton"> El id puede ser cualquiera. Luego, en el archivo modifier.js en el momento en que se necesiten estos botones (modifyCreate, modifyUpdate, modifyUpdate modifyShow) ) hay que llamar a la siguiente funcin, que le asignar el comportamiento a dicho botn:
setIMGAsCollapsable(pIMGElement, pIdCollapsableParent, pIdCollapsableElement, pDsCollapsedIconSRC, pDsUncollapsedIconSRC, pDsCollapsedTitle, pDsUncollapsedTitle, pIdInitiallyCollapsed) Donde: pIMGElement es una referencia al objeto DOM del tag IMG que ser clickeado para ocultar o mostrar pIdCollapsableParent es el Id del parent que contiene todo el conjunto onjunto (imagen y objeto a ocultar) pIdCollapsableElement es Id del elemento a ocultar
ConsistGPA
Pgina 19 de 37
pDsCollapsedIconSRC Icono a mostrar cuando al objeto se encuentra collapsado (oculto ->) pDsUncollapsedIconSRC Icono a mostrar cuando al objeto se encuentra desplegado (visible ^) pDsCollapsedTitle Texto a mostrar cuando se pasa por encima de la imagen y el objeto est oculto pDsUncollapsedTitle Texto a mostrar cuando se pasa por encima de la imagen y el objeto est visible pIdInitiallyCollapsed Indica si inicialmente se e configura como oculto o no (true/false) pBeforeCollapseUnCollapse Funcin a ejecutar antes de colapsar/descolapsar pAfterCollapseUncollapse Funcin a ejecutar despus de colapsar/descolapsar
Ejemplo de llamado a la funcin: funci setIMGAsCollapsable(document.getElementById document.getElementById("collapsableButton"), ("collapsableButton"), "collapsableParent", ", "collapsablePanel", "./themes/default/ES/imagenes/mas.png", "./themes/default/ES/imagenes/menos.png", "Mas datos", "Menos datos", true, null, null); // si no se ingresan los ltimos dos parmetros, parmetros, se //toman por defecto null donde ./themes/default/ES/imagenes/ es la ruta relativa al directorio por defecto donde se encuentran las imgenes de GPA. Para aplicar estas propiedades a todos los botones colapsables dentro de un iterativo, habra a que hacerlo de la siguiente manera: function setCollapsableButtons(){ var xFunction = function(pIterative){ setIMGAsCollapsable(findChildById(pIterative,"collapsableButton"), pIterative.id, "collapsablePanel", "./themes/default/ES/imagenes/mas.png", "./themes/default/ES/imagenes/menos.png", ./themes/default/ES/imagenes/menos.png", "Mas datos", "Menos datos", true); } processIterative("NombreDelIterativo",xFunction); }
ConsistGPA
Pgina 20 de 37
setIMGCollapsableForIterative(pIMGElement, pIdIterative, pDsCollapsedIconSRC, pDsUncollapsedIconSRC, pDsCollapsedTitle, pDsUncollapsedTitle, pIdInitiallyCollapsed, pIdInitiallyCol pAction) Donde:
pIMGElement es una referencia al objeto DOM del tag IMG que ser clickeado para ocultar o mostrar pIdIterative es el nombre del iterativo pDsCollapsedIconSRC Icono a mostrar cuando al objeto se encuentra collapsado (oculto ->) pDsUncollapsedIconSRC Icono a mostrar cuando al objeto se encuentra desplegado (visible ^) pDsCollapsedTitle Texto a mostrar cuando se pasa por encima de la imagen y el objeto est oculto pDsUncollapsedTitle Texto a mostrar cuando se pasa por encima de la imagen y el objeto est visible pIdInitiallyCollapsed Indica si inicialmente se configura como oculto o no (true/false) pAction Puede ser "ninguno", va a ocultar ocultar todas las ocurrencias del iterativo, "primero", va a ocultar todos los elementos menos el primero del iterativo, "ultimo" va a ocultar todos los elementos menos el ltimo del iterativo, o una funcin, uncin, a la cual se le va a asignar a un processIterative(), processIterativ esta funcin deber definir la lgica de qu datos mostrar/ocultar ostrar/ocultar cuando se colapse el iterativo. Cuando descolapse, de muestran todos sus elementos. pBeforeCollapseUnCollapse Funcin a ejecutar antes de colapsar/descolapsar pAfterCollapseUncollapse Funcin a ejecutar despus de colapsar/descolapsar
Ejemplos de llamado a la funcin: funci Para ocultar todos menos el ltimo: setIMGCollapsableForIterative(document.getElementById("imageID"), setIMGCollapsableForIterative(document.getElementById(" "), "iterativeName" /*( ej:lsProcesos lsProcesos)*/, "./themes/default/ES/imagene "./themes/default/ES/imagenes/mas.png", "./themes/default/ES/imagenes/menos.png", "Mas datos", "Menos datos", true, "ultimo"); Para ocultar las instancias del iterativo en base a una funcin:
Ocultar todas las ocurrencias de un iterative cuyo campo dsField est est vaco var xFunction = function(pIterative){ if(findChildById(pIterative," if(findChildById(pIterative,"iterativeName/dsField").value ").value != ''){ pIterative.style.display = ""; } else { pIterative.style.display = "none"; } };
ConsistGPA
Pgina 21 de 37
setIMGCollapsableForIterative(document.getElementById("imageID"), " iterativeName ", "./themes/default/ES/imagenes/mas.png", "./themes/default/ES/imagenes/menos.png", "Mas datos", "Menos datos", true, xFunction)
function setFormatToIterative(pIterativeName,pLsRows,pCursorStyle){ var xFila = "par"; var xFunction = function(pIterative){ if(xFila == "par"){ for(var i=0;i<pLsRows.length; i++){ var xRow = findChildById(pIterative,pLsRows[i]); xRow.setAttribute("class","tablaFilaPar"); if(pCursorStyle){ xRow.style.cursor = pCursorStyle; } } xFila = "impar"; } else { for(var i=0;i<pLsRows.length; i++){ var xRow = findChildById(pIterative,pLsRows[i]); xRow.setAttribute("class","tablaFilaImpar"); if(pCursorStyle){ xRow.style.cursor = pCursorStyle; } } xFila = "par"; } } processIterative(pIterativeName,xFunction) } Donde pIterativeName es el el nombre del iterativo a aplicar el formato, pLsRows es una lista con los ids de las filas dentro del iterativo (los <TR>, para que a todos se les aplique el mismo color), y pCursorStyle es el estilo del cursor, que por defecto ser pointer (hand). Hay que tener en cuenta de llamar a esta funcin al insertar un nuevo elementoal iterativo o eliminarlo, esto se hace agregando al botn del HTML que agrega o elimina una instancia del iterativo: Ejemplo de llamado a la funcin desde js: setFormatToIterative("nombreIterativo nombreIterativo",["Fila1","Fila2"],"auto"); "],"auto");
ConsistGPA
Pgina 22 de 37
En el Insertar: <input value="Nuevo Elemento" type="button" class="botonadds" onClick="cloneMultipleNode(consist_findElement ('nombreIterativo'), (' '), consist_findElement ('tablePlacenombreIterativo')); ('tablePlace setFormatToIterative('nombreIterativo nombreIterativo', ['Fila1','Fila2'],'auto')" 'auto')" name="button" id="button" > Tambin sera deseable que, como ocurre en el browse, se coloree el iterativo en el cual se posiciona el cursor. Esto se puede hacer directamente sobre el HTML, en este ejemplo ejemplo se mostrar cmo hacerlo cuando hay una y dos filas, para n filas, el concepto es el mismo. Se deber llamar a la funcin lineaOver(pTarget) en el evento onmouseover, una vez para cada fila de la tabla del iterativo base, dnde pTarget sera cada una de las filas; y lineaOut(pTarget) en el evento onmouseout Para una fila: <TR onmouseover="lineaOver(this)" onmouseover="lineaOver(this) onmouseout="lineaOut(this)" ></TR> Para dos filas: // se ejecuta lineaOver y lineaOut de la fila actual y la siguiente <TR onmouseover="lineaOver(this);lineaOver(this.nextSibling);" onmouseout="lineaOut(this);lineaOut(this.nextSibling);" ></TR> // se ejecuta lineaOver y lineaOut de la fila actual y la anterior <TR onmouseover="lineaOver(this);lineaOver(this.previousSibling);" onmouseover="lineaOver(this);lineaOver(this. ;" onmouseout="lineaOut(this);lineaOut(this.previousSibling ="lineaOut(this);lineaOut(this.previousSibling);" ></TR>
Tambin se puede hacer con javascrip (es recomentable, sobretodo si el iterativo base tiene varias filas): filas) En cada fila del iterativo: <TABLE id =nombreIterativo style=display:none> style=display:n <TR onmouseover="colorearIterativo colorearIterativo(this,true)" " onmouseout=" colorearIterativo (this,false);" (this ></TR> <TR onmouseover="colorearIterativo colorearIterativo(this,true)" " onmouseout=" colorearIterativo (this,false);" (this ></TR> . . . </TABLE>
Funcin de javascript; function colorearIterativo(pEventSource, pIsOver){ var xParent = pEventSource.parentNode; var xRow = xParent.firstChild; .firstChild; while (xRow != null){ if(pIsOver) { lineaOver(xRow); lineaOver(
ConsistGPA Pgina 23 de 37
COPIAR FORMULARIOS
Para copiar un formulario seguir los siguientes pasos: Exportar la definicin del formulario Modificar el archivo zip generado asignando a la carpeta: carp ARCHIVO zip -> \files files\docGenerator\app\RR1 el l cdigo del nuevo formulario, en el ejemplo anterior RR1 sera el cdigo del nuevo formulario. Modificar el data.xml reemplazando el cdigo del nuevo formulario ARCHIVO ZIP -> > data.xml Modificar el config.xml reemplazando el cdigo del nuevo formulario ARCHIVO ZIP -> \files files\docGenerator\app\R76\config.xml Reemplazar los 2 archivos modificados en el archivo zip exportado Importar el archivo zip modificado y ya queda el FORMULARIO COPIADO! Modificar el nuevo formulario desde Visio para cambiarle nombre y todos los cambios necesarios.
Pgina 25 de 37
Otra opcin para agregar campos es: 1. Exportar la definicin del formulario 2. Exportar los datos del formulario 3. Eliminar los DATOS del formulario 4. Modificar el formulario agregando los campos 5. Importar los datos del formulario
INDICAR COMBOS FILTRADOS QUE DEBEN SER CARGADOS AUNQUE ESTEN OCULTOS.
Cuando un combo est dentro de un tag que est oculto, ste combo no se cargar para optimizar la carga. Si ste combo no se muestra nunca esta funcionalidad optimiza la carga pero si en algn momento se tiene que mostrar como en el caso del uso de solapas ser necesario especificar que combos se deben cargar aunque estn ocultos. Realizar lo siguiente: Crear en el HTML un tag INPUT de tipo HIDDEN que contenga como valor una lista separada por @@ de los IDs de los campos y que finalice con @@. El ID de este campo oculto debe ser ignoreInputHidden <input type=hidden id=ignoreInputHidden value=combo1@@combo2@@> Otra opcin es utilizar el estilo style=visibility:hidden en lugar de style=display:none en un div que contenga al combo que filtra.
Pgina 27 de 37
Ejecucin de la regla:
executeComponentAjax(pCdComponent, pCdVersion, pLsComponentINParameters, pCallbackFunction, pLsCallbackFunctionParameters, pShowWaitMessage, p pDsWaitMessage)
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 pLsComponentINParameters puede ser null 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 asincrnic asincrnica, a, 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 q que ue se deseen.
Donde success, es true, si la regla ejecut correctamente, y false si ocurri algn error durante la ejecucin de la regla. El nodo resultado que se enva como parmetro a la funcin que se ejecuta cuando el ajax ejecuta correctamente, es el resultado de la ejecucin cucin de la regla, devuelto en esta estructura xml, a partir del tag RESULT.
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 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 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">2012level="8">2012 06-01</ NombreParmetro > java.sql.Timestamp: < NombreParmetro class="java.sql.Timestamp" isNull="false" id="00000000000000000001" level="8">2012-06-01 01 00:00:00.0</ NombreParmetro > Boolean: < NombreParmetro class="java.lang.Boolean" isNull="false" id="00000000000000000001" level="8">false</ NombreParmetro > Null: < NombreParmetro
Pgina 29 de 37
<item class="java.lang.String" isNull="false" id="00000000000000000004" level="7">Strign3</item> <item class="java.lang.String" isNull="false" id="000000000 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> level="7">1</it <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 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 >
Pgina 30 de 37
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 ot otra ra 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" i id="00000000000000000002" d="00000000000000000002" level="7">Clave</key> <value class="java.lang.String" isNull="false" id="00000000000000000003" level="7">Valor</value> </entry>
Funciones primitivas: No se describirn las funciones primitivas para manipular datos XML, solo daremos algunos ejemplos:
xElemntoXML.firstChild.nodeValue // Devuelve el valor del 1er hijo de la raz xElemntoXML.childNodes // Devuelve el arreglo de hijos xElemntoXML.attributes[i].value // Devuelve el valor del atributo de la posicin i de un elemento xml xElemntoXML.getElementsByTagName(tagName) // Obtiene los elementos con el tagName indicado. Etc.
Funciones desarrolladas por Consist, 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 h pXMLPath. Este path puede especificar un camino de varios niveles separando los nombres de los tags por /. : getXMLElement(pXMLRoot, NombreParmetro/entry/key); Ej (Mapa): (Lista): getXMLElement(pXMLRoot, NombreParmetro/item); (ClaseSimple) getXMLElement(pXMLRoot, ment(pXMLRoot, NombreParmetro);
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 ndo los nombres de los tags por / Ej (Mapa): getXMLElementValue (pXMLRoot, nombreParmetro/entry/key); (Lista): getXMLElementValue (pXMLRoot, nombreParmetro/item); (ClaseSimple) getXMLElementValue (pXMLRoot, nombreParmetro);
findXMLChild(pXMLRoot, t, pNodeName): Devuelve el primer subelemento de un nodo XML con tag llamado pNodeName Ej: findXMLChild(pXMLRoot, nombreParmetro nombreParmetro) findXMLChild(pXMLRoot, Key) ) findXMLChild(pXMLRoot, value value)
getXMLAttribute(pXMLNode, pAttributeName) pAttributeName): Devuelve el valor de un atributo llamado pAttributeName de un nodo XML Ej: Var xElement = getXMLElement(pXMLRoot, nombreParmetro); getXMLAttribute (xElement , level level) getXMLAttribute (xElement, class ) getXMLAttribute (xElement, isNull 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:
Pgina 32 de 37
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 uedo 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 ministracin 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, Ent 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 siste 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, de 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 aje (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 id="tipoPasaje" onChange=contarPasajes(this) >
function contarPasajes(pEventSource){
Pgina 33 de 37
/* 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 val valor or 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 nroD nroDesde). esde). 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 eje ejecutndose cutndose normalmente (no se congela ni espera a que termine el ajax) */ } de este element es nulo, para evitar un
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 d decir, ecir, 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 m menos, enos, 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 r requerimiento equerimiento 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 pr proveedores, oveedores, qu proveedores proveen dicho producto.
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" ype="text" class="text_1" name=" name="claseItem" id=" claseItem " > Marca de producto (asociado a una tabla): <INPUT type="text" class="text_1" name=" 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=" 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=" name="claseItem" id="claseItem " onChange=actualizarProveedores() > <INPUT type="text" class="text_1" name=" name="marcaItem" id="marcaItem " onChange= actualizarProveedores() ualizarProveedores() >
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 getXMLChildrenTe tXMLChildrenTexts */ var xIdProveedores = getXMLChildrenTexts(pXMLRoot, pIdProveedores/item); pIdProveedores var xDsProveedores = getXMLChildrenTexts(pXMLRoot, p pDsProveedores Proveedores/item); //Buscamos el combo de proveedores: Var xSelect = document.getElementById( 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 = ""; Pgina 35 de 37
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( document.getElementById(claseItem).value; var xMarcaItem = document.getElementById(marcaItem).value; // Llamamos al ajax. Los parmetros no indicados de toman como null. executeComponentAjax(ProveedoresPorClaseYMarca ProveedoresPorClaseYMarca, 1, [pClaseProducto, xClaseItem, xC pMarcaProducto, xMarcaItem], , xFunction xFunction); /*Listo, en este momento el ajax empieza a ejecutarse. Cuando termina, se ejecuta la funcin xFunction. Todo o lo que sigue a partir de esta lnea, seguir ejecutndose normalmente (no se congela ni espera a que termine el ajax) */ }
Se e puede usar Ajax para validar datos dinmicamente. Pero, recordar, que mientras se ejecuta el Ajax, la pgina sigue activa. Entonces, sera necesario, cuando se ejecute el Ajax, bloquear los botones submit, y cuando termine de ejecutar, desbloquearlos. No o es necesario definir la funcin que se ejecuta al retorna el Ajax dentro de la funcin que ejecuta el Ajax. Podra ser una funcin aparte.
Pgina 37 de 37