OBJETO WEB PANEL 246 Características • Permiten definir consultas interactivas a la base de datos. • Son flexibles por lo que se prestan para múltiples usos. Los web panels son objetos GeneXus que permiten al usuario en tiempo de ejecución, realizar interactivamente consultas a la base de datos a través de una pantalla. El término “interactivamente” se refiere a que el usuario podrá ingresar en la pantalla de un web panel una y otra vez distintos valores de filtros, y consultar a continuación los datos que concuerden con los mismos. Además, sobre los datos consultados, el usuario podrá realizar distintas acciones, como veremos. Los web panels no permiten la actualización de la base de datos, sino sólo su consulta1. El objetivo primordial de este objeto GeneXus es la definición de consultas interactivas a la base de datos, sin embargo se trata de un objeto muy flexible por lo que se presta para diversos usos. En este capítulo estudiaremos algunos detalles de este tipo de objeto. -------------------------------------------------------------------------------------------------------------------A menos que se utilicen en combinación con los business components (estudiados más adelante) 1 247 Elementos • Algunos de ellos son: • Web Form • Reglas • Condiciones • Subrutinas • Eventos • Propiedades • Ayuda • Documentación Los elementos de los web panels son: Web Form: Cada web panel contiene un form Web, el cual debe ser diseñado por el analista agregándole variables, atributos, así como otros controles, para que el usuario pueda interactuar con el mismo. Reglas: Las reglas de un web panel permiten definir ciertos comportamientos puntuales de dicho objeto. Por ejemplo, declarar qué parámetros recibe, definir qué variables no queremos que sean aceptadas en el form sino utilizadas para desplegar información, etc. Condiciones: Es para definir las condiciones que deben cumplir los datos a ser recuperados (filtros). Subrutinas: Son rutinas locales al web panel. Eventos: Los web panels emplean la programación orientada a eventos. Este tipo de programación permite definir código ocioso, que se activa en respuesta a ciertas acciones provocadas por el usuario o por el sistema. En esta sección de un web panel es donde se define el código ocioso asociado a los eventos que pueden ocurrir durante la ejecución del web panel. Propiedades: Son características a comportamiento general del web panel. ser configuradas para definir ciertos detalles referentes al Ayuda: Permite la inclusión de texto de ayuda, que los usuarios podrán consultar en tiempo de ejecución del web panel. Documentación: Permite la inclusión de texto técnico como documentación para los desarrolladores. 248 Clasificación de web panels • Web panels de Entrada • Web panels de Salida • Web panels Mixtos Todo web panel tiene un form asociado, y en el mismo, contrariamente al comportamiento del form de una transacción, los atributos que se incluyan serán de salida, y las variables que se incluyan serán de entrada. Es fácil de comprender que el objetivo del form de un web panel es exactamente el contrario al objetivo del form de una transacción, ya que: • a través del form de una transacción se ingresan los valores de los atributos en la base de datos. • a través del form de un web panel, se consultan / recuperan los valores de los atributos de la base de datos. Es por esto que los atributos son de entrada en las transacciones y de salida en los web panels. Y en lo que respecta a las variables, las mismas son de salida en las transacciones y de entrada en los web panels. La siguiente clasificación describe los distintos usos posibles de los web panels: · Web panel de entrada: le damos este nombre a un web panel que tiene la única función de aceptar valores digitados por el usuario (esto significa que su form contendrá únicamente variables). · Web panel de salida: le damos este nombre a un web panel que tiene la única función de mostrar información (esto significa que su form contendrá únicamente atributos, pudiendo también contener variables a las cuales se les haya cambiado el comportamiento por defecto de ser de entrada, definiéndolas de salida y cargándoles valores explícitamente). · Web panel mixto: le damos este nombre a un web panel que permite tanto ingresar valores como mostrar información (en este caso su form contendrá tanto variables como atributos, o bien sólo variables, algunas con el comportamiento por defecto de ser de entrada y otras definidas explícitamente de salida y cargándoles valores). Vale aclarar que esta clasificación es independiente de la herramienta; es decir, GeneXus internamente no clasifica a los web panels. 249 Web panel de Entrada Event Enter ¾ Las variables adquieren el valor digitado luego de presionar algún botón. Event Enter RList.call( &NombreClienteInicial, &NombreClienteFinal ) endevent Denominamos web panels de entrada a aquellos web panels cuya única función es que el usuario realice ingresos de valores por medio de los mismos. Por lo tanto, sus forms contendrán solamente variables. Por ejemplo, un web panel de entrada puede contener dos variables &NombreClienteInicial y &NombreClienteFinal como se muestra arriba. En tiempo de ejecución, el usuario podrá ingresar valores en las variables &NombreClienteInicial y &NombreClienteFinal dado que en los web panels las variables son por defecto de entrada. En el evento Enter del web panel (asociado al botón Confirm), se invocará a un reporte, al cual se le pasarán por parámetro las variables &NombreClienteInicial y &NombreClienteFinal para que el reporte liste todos los clientes cuyos nombres se encuentren en el rango solicitado: Event Enter RListClienteRange.call( &NombreClienteInicial, &NombreClienteFinal ) EndEvent // Enter De modo que la definición de este web panel de entrada es para que el usuario ingrese el rango de clientes a listar, y al seleccionar el botón Confirm, se ejecute el reporte correspondiente. 250 Web panel de Salida tabla base: CLIENTE Regla: parm(in:ClienteId); Denominamos web panels de salida a aquellos web panels cuya única función es exhibir datos. Para que un web panel únicamente muestre datos, su form debe contener solamente atributos, ya que los atributos en los forms de web panels son indefectiblemente de salida1. Otra posibilidad es incluir en el form variables, pero habrá que cambiarles su comportamiento por defecto de ser de entrada, a ser de salida, y cargarles valores explícitamente2. El web panel mostrado arriba ha sido creado para exhibir los datos de un cliente. Se necesita invocarlo desde otro objeto, pasándole por parámetro el código del cliente del cual se quiere mostrar la información. Para resolver esto, una vez creado el web panel “Ver Datos del Cliente”: • se han agregado los atributos que se desean visualizar en su form • se ha definido la regla: Parm(in: ClienteId); en la sección de reglas del objeto Tan sólo definiendo esto obtendremos el comportamiento deseado. ¿Qué concluirá GeneXus acerca de este web panel, cuando lo especifiquemos? Primeramente GeneXus observará que los atributos incluidos en el form pertenecen a las tablas CLIENTE y PAIS respectivamente. El siguiente diagrama de Bachman explicita la relación entre ambas tablas: -------------------------------------------------------------------------------------------------------------------CLIENTE PAIS Al contrario de lo que sucede con los atributos en las transacciones (salvo los inferidos o los que tienen regla noaccept o propiedad Enabled deshabilitada). 2 El comportamiento por defecto de las variables también es opuesto entre Web Panels y Transacciones. 1 251 Teniendo en cuenta la relación entre las tablas involucradas, GeneXus descubrirá que deberá recorrer la tabla CLIENTE y acceder a la tabla PAIS por el concepto de tabla extendida. La tabla PAIS no podrá ser elegida para ser recorrida porque su tabla extendida no incluye a la tabla CLIENTE. Así es que GeneXus determinará un for each asociado al web panel, en este caso con tabla base CLIENTE; nosotros no escribimos el for each, pero GeneXus lo infiere automáticamente. A su vez, como en la regla parm definida en el web panel se recibe un atributo, el mismo actuará como filtro por condición de igualdad. Es decir, que al ejecutarse la recorrida de la tabla CLIENTE (accediendo a la tabla PAIS para traer el nombre de país), se filtrará por el código de cliente recibido por parámetro. Concluyendo, se recorrerá la tabla CLIENTE, con condición de filtro por el cliente recibido en la regla parm y se mostrarán los datos en la pantalla. El nombre del país del cliente (PaisNombre) se inferirá por el concepto de tabla extendida y se mostrará también en la pantalla. Decimos que este web panel tiene tabla base, y la misma es CLIENTE. Esto significa que el web panel tiene un for each implícito / automático asociado, cuya tabla base es CLIENTE. 252 Web panel de Salida grid: Se cargan los registros de la base de datos correspondientes en archivo temporal Regla: parm(in:ClienteId); tabla base: FACTURA Este web panel ha sido creado para mostrar las facturas de determinado cliente. Se necesita desde otro objeto, invocar a éste, pasándole por parámetro el código del cliente del cual se quieren mostrar sus facturas. Para resolver esto, una vez creado el web panel “Ver Facturas Cliente”: • se han agregado los atributos que deseamos visualizar en su form (utilizando el control grid para mostrar las N facturas del cliente en cuestión) • se ha definido la regla: Parm(in: ClienteId); en la sección de reglas del objeto Este web panel, a diferencia del anterior no es plano, pero continúa siendo un web panel de salida, ya que lo único que hace es mostrar datos de la base de datos, sin permitir que el usuario ingrese nada. Cuando se incluye un grid en un form, se está indicando que se va a mostrar una cantidad indefinida de datos (en este caso, facturas). Dado que en este web panel hay involucrados atributos de las tablas CLIENTE y FACTURA y que la relación entre ambas tablas es: FACTURA CLIENTE GeneXus determinará que recorrerá la tabla FACTURA y accederá a la tabla CLIENTE por el concepto de tabla extendida. La tabla CLIENTE no podrá ser elegida para ser recorrida porque en su tabla extendida no se encuentra la tabla FACTURA. De modo que GeneXus determinará un for each implícito asociado al web panel, con tabla base FACTURA, accediendo a la tabla CLIENTE por el concepto de tabla extendida. Como en la regla parm definida en el web panel, se recibe un atributo, el mismo actuará como filtro por igualdad. Es decir, que al ejecutarse la recorrida a la tabla FACTURA accediendo a la tabla CLIENTE, se filtrará por el código de cliente recibido por parámetro. Decimos que este web panel tiene tabla base, y la misma es FACTURA. Esto significa que el web panel tiene un for each implícito/automático asociado, cuya tabla base es FACTURA. 253 Web panel Mixto: “Work With” •Event Enter •Evento Usuario Tabla Base: CLIENTE Las variables adquieren el valor digitado luego de presionar algún botón generales versus particulares Los web panels no tienen por qué ser sólo de entrada o sólo de salida. El web panel que se muestra arriba es de entrada/salida (mixto), su form contiene tanto variables como atributos. La funcionalidad de este web panel es cargar en el grid los datos de todos los clientes cuyos nombres cumplan con la condición de filtro especificada. La idea es digitar sobre la variable &ClienteNombre el valor de filtro deseado, y a continuación presionar el botón Buscar para que se ejecute la consulta en el servidor y el resultado de la misma sea cargado en la página. El evento asociado al botón Buscar puede ser el Evento Enter (evento del sistema) ó cualquier evento definido por el usuario (volveremos sobre esto más adelante). Las condiciones de filtro pueden definirse de dos maneras posibles: • A nivel de un grid en particular (botón derecho sobre el grid/Conditions): de hacerlo así, se tratará de condiciones particulares para ese grid (las que se muestran arriba). • A nivel de todo el web panel (en la sección Conditions del objeto): de hacerlo así, se tratará de condiciones globales, es decir que aplicarán a todos los grids del web panel en los que tenga sentido aplicarlas (más adelante veremos web panels con múltiples grids). En el web panel del ejemplo tenemos un sólo grid, por lo cual ambas opciones serían equivalentes desde el punto de vista lógico. Sin embargo es recomendable escribir las condiciones a nivel del grid ya que en un futuro podrán agregarse más grids al web panel. Además teniendo las condiciones a nivel del grid se optimiza al momento de la especificación (ya que en caso contrario, GeneXus deberá estudiar para cada grid si aplicar las condiciones generales a ese grid particular o no). ¿Qué lógica inferirá GeneXus al momento de la especificación del Web Panel? Como los atributos involucrados en el web panel pertenecen algunos a la tabla CLIENTE y otros a la tabla PAIS, y en la tabla extendida de CLIENTE está la tabla PAIS, GeneXus determinará que la tabla a recorrer es CLIENTE y que accederá por su extendida a la tabla PAIS para cargar el valor del atributo PaisNombre. Es decir, GeneXus determinará un for each implícito asociado al web panel, con tabla base CLIENTE. Las condiciones definidas antes (a nivel de grid) se incluirán en el for each implícito (como cláusulas where), de modo tal que al ejecutarse la consulta, se recorrerá la tabla CLIENTE, filtrando por dichas condiciones. Es importante considerar que tanto en las condiciones globales del web panel, como en las condiciones locales a un grid de un web panel, es posible utilizar la cláusula when al igual que cuando se definen filtros en los objetos reportes y procedimientos. 254 Web panel ¿con tabla base? • Decimos que un web panel es “con tabla base” cuando GeneXus puede determinar un for each implícito asociado a él. • Es decir, si bien el analista no escribe un for each explícitamente en el web panel para efectuar la consulta, GeneXus lo determina automáticamente (por eso lo llamamos: for each implícito). • Tabla base del for each implícito = Tabla base del web panel. • Un Web Panel es “sin tabla base” cuando GeneXus no puede determinar una tabla de la base de datos a recorrer para mostrar la información que se presenta en el form. • En este caso en el form solamente aparecen variables (y no atributos). Un web panel es con tabla base cuando de los atributos que aparecen, GeneXus puede determinar una tabla de la base de datos a recorrer para, recuperando sus registros, mostrar la información que aparece en los atributos del web panel. De este modo, es como si hubiéramos escrito un for each para navegar esa tabla base y trabajar con algunos atributos de la misma, y de la extendida. Si en el Web Panel no aparecieran atributos, sino solo variables, evidentemente GeneXus no podrá determinar una tabla a ser navegada. En este caso el web panel será sin tabla base. 255 Orden de los datos a recuperar • Botón derecho sobre el grid: Para definir que una consulta se efectúe ordenando por ciertos atributos, y por ende que los datos extraídos de la consulta se muestren ordenados con dicho criterio, se debe hacer clic con el botón derecho del mouse sobre el grid, y seleccionar el ítem Order del menú pop up que se muestra arriba. A continuación, se presentará el diálogo para que se ingresen los atributos por los que se desea ordenar. Definir esto es equivalente a definir la cláusula order en el comando for each, y se aplica todo lo visto en dicho tema: desde que para ordenar en forma descendente por un atributo se debe encerrar el atributo entre paréntesis (), la creación de índices temporales cuando no exista un índice físico correspondiente a los atributos de ordenamiento, así como la posibilidad de utilizar la cláusula when para condicionar la aplicación de ese order. En nuestro web panel “Trabajar Con Clientes” ordenamos los clientes que se listan en el grid por ClienteNombre. El poder definir order para un grid permite entre otras cosas optimizar la consulta, cuando se establecen condiciones de filtro. Así, si en las conditions generales y/o las del grid particular, siendo la tabla base CLIENTE establecemos los filtros, teniendo dos variables ingresadas por el usuario: ClienteNombre >= &clienteNombreInicio; ClienteNombre <= &clienteNombreFin; Entonces, de no especificar un orden por ClienteNombre, se deberá recorrer toda la tabla, de principio a fin, para cargar los registros que cumplan con las condiciones. Especificando un order optimizamos la consulta. Nota: Solamente si el form del web panel no tiene ningún grid (atributos sueltos), y se necesita definir un orden específico para la consulta, se contará con la posibilidad de definir en la sección de reglas del web panel, la regla de sintaxis: order(att1, att2, attN); siendo att1, att2, attN: la lista de atributos que define el orden de la consulta. 256 Eventos en web panels • En los web panels se utiliza la programación dirigida por eventos. • Eventos disponibles en web panels: – Evento Start – Evento Refresh – Evento Load – Evento Enter – Eventos de Usuario – Evento Click asociado a control Dado que la programación de los Web Panels está dirigida por eventos, para poder programar adecuadamente un objeto de este tipo es necesario conocer los eventos existentes y el momento y orden en que éstos se disparan. 257 Evento Start • Es un evento del sistema, que ocurre automáticamente siempre que se hace Get o Post y es el primer evento que se ejecuta. • No se conocen valores de atributos, salvo los recibidos por parámetro. Esto se debe a que aún no se ha efectuado la consulta. • Ejemplo: se puede utilizar para que un control del form no aparezca visible, para cargar un bitmap, para asociarle un Link a otro control, etc.: Event Start &var.Visible = 0 &Update = LoadBitmap("images/edit.gif") newControl.Link = Link(TCliente) endevent En el ejemplo, tendremos 3 controles en el form: la variable de nombre var, la de nombre Update de tipo Bitmap y un control de nombre newControl que puede ser, por ejemplo, un control imagen. En el evento Start se le asigna a la propiedad Visible del control variable &var el valor 0, indicando que no deberá verse en el form. A su vez, a la variable de tipo bitmap, &Update, se le carga la imagen que contendrá, y al control que suponemos imagen, newControl, se le define la propiedad Link, de manera tal que cuando el usuario haga clic sobre el control, se invocará a la transacción “Cliente”. 258 Evento Refresh • El evento Refresh es un evento del sistema • Se ejecuta cada vez que se realiza un Get o Post. • Provoca que se ejecute la consulta a la base de datos. • Es decir, al ocurrir el evento Refresh, se ejecuta lo codificado en dicho evento, y a continuación se ejecuta la consulta a la base de datos. Viene seguido siempre del evento Load. 259 Evento Load • Cada vez que se ejecute el evento Refresh en un web panel, seguidamente se ejecutará el evento Load. • La cantidad de veces que el evento Load será ejecutado, dependerá de si el web panel tiene tabla base o no la tiene: • Tiene tabla base: • Cuando aparecen atributos que le permiten automáticamente determinar que se desea navegar una tabla determinada de la base de datos • El evento Load se ejecutará N veces • No tiene tabla base: • Cuando no ocurre lo anterior (en el form solo hay variables) • El evento Load se ejecutará solamente una vez. Cuando el web panel es con tabla base, al producirse el evento Refresh se accede a la base de datos, a esa tabla base (la asociada al web panel), y se la recorre cargando los registros que cumplan las condiciones (conditions del grid y generales). Ocurrirá en ese proceso un evento Load por cada registro en el que se esté posicionado, inmediatamente antes de cargarlo. Esto nos permite realizar alguna operación que requiera de ese registro (y de su extendida), antes de efectivamente cargarlo en el grid. Inmediatamente luego de ejecutado el código asociado al evento Load, se cargará la línea del grid y se pasará el puntero al siguiente registro de la tabla base, para realizar lo mismo (evento Load, carga de la línea). Este proceso se repetirá hasta cargar todas las líneas del grid. Si un web panel es sin tabla base, GeneXus no puede determinar automáticamente una tabla de la base de datos a recorrer para mostrar la información que se presenta en el form. En este caso en el form solamente aparecen variables (y no atributos) y también ocurrirán los eventos Refresh y Load, sólo que el evento Load se ejecutará una única vez, dado que no se estará posicionado en ningún registro de ninguna tabla. 260 Evento Load en web panel con tabla base Luego del evento Refresh se ejecuta el evento Load N veces: una vez por cada registro de la tabla base leído para ser cargado en la línea del grid Por cada registro leído en la consulta efectuada a la base de datos, se disparará el evento Load (ejecutándose el código incluido en el mismo, y cargándose a continuación una línea en el grid con los datos asociados al registro). 261 Evento Load en web panel con tabla base: ejemplo Si en el grid que muestra los clientes que cumplen con las condiciones de filtro, quisiéramos agregar una columna al final, que marque que el cliente es moroso (deudor) si su saldo es mayor a $10.000, es decir, que en ejecución sobresalga su condición de moroso apareciendo un literal DEUDOR en ese caso, alcanza con agregar una variable &tipo al grid, de tipo Character(10) y cargarla en el evento Load del web panel como se muestra arriba. Para cada registro de la tabla base CLIENTE que se vaya a cargar como línea en el grid, se ejecutará el código del evento Load, cargándose en la columna &tipo el valor DEUDOR únicamente si el saldo de ese cliente que va a listarse supera los $10.000. Luego, si para cada cliente del grid además de mostrar su nombre, país, sexo, saldo y tipo, queremos mostrar la cantidad de facturas que se le han emitido, alcanza con agregar una variable &cantidad al grid, e incluir en el código del evento Load, el for each para contar esas facturas. Observar que el for each definido en el evento Load estará anidado al for each implícito (el de la tabla base), por lo que se efectuará un join, recorriéndose solamente las facturas de ese cliente, el que se está cargando. 262 Evento Load en web panel sin tabla base • En un web panel sin tabla base, el evento Load se ejecutará solamente una vez. Evento Refresh Evento Load Que el web panel no tenga tabla base, significa que no tiene un for each implícito asociado; por lo tanto, cuando se ejecute el evento Refresh, no comenzará a ejecutarse ninguna consulta; se ejecutará el código asociado al evento Refresh, y a continuación se ejecutará el código asociado al evento Load, una única vez. Aquí es donde tendremos que cargar el grid, consultando la base de datos con un for each explícito. A continuación vemos el código de este evento. 263 Evento Load en web panel sin tabla base: ejemplo Comando (que solo puede ir dentro de evento Load) para efectivamente cargar una línea con el valor que tengan las variables en ese momento. El objetivo del comando LOAD dentro del evento Load es cargar efectivamente una línea en el grid. Una vez que se hayan asignado valores a todas las variables que sean necesarias, y se desee agregar la línea al grid, deberá ejecutarse el comando LOAD. Solamente se puede especificar el comando LOAD dentro del evento Load del grid de un web panel y en ningún otro lado. Event Load for each &ClienteId = ClienteId &ClienteNombre = ClienteNombre &ClienteSexo = ClienteSexo &ClienteSaldo = ClienteSaldo if ClienteSaldo > 10000 &tipo = ‘DEUDOR’ else &tipo = ‘’ endif &cantidad = 0 for each defined by FacturaFecha &cantidad += 1 endfor Load /* LUEGO DE HABER CARGADO TODAS LAS VARIABLES CON LOS VALORES CORRESPONDIENTES A LA LÍNEA A SER CARGADA EN EL GRID, DEBEMOS INCLUIR EL LOAD, EL CUAL AGREGARÁ EFECTIVAMENTE LA LÍNEA AL GRID. */ endfor Endevent COMANDO Si en la codificación del evento Load definimos comandos For each y asignamos valores a las variables en las iteraciones pero no incluimos el comando LOAD, en tiempo de ejecución estaremos asignando una y otra vez valores a las variables, pero no se estarán agregado líneas en el grid (solamente quedará una línea en el grid con los últimos valores cargados en las variables). Por esta razón es muy importante no olvidar escribir este comando en el lugar apropiado. 264 Evento Enter • Cuando se inserta un nuevo botón en el form de un Web Panel, por defecto aparece con el Caption “Confirm” y aparece asociado al evento del sistema Enter. • El evento Enter puede asociarse a cualquier botón, atributo, imagen, text block, en la propiedad de los controles: OnClickEvent. • De modo que si se necesita ejecutar acciones cuando el usuario final haga clic en el control asociado, en este evento deberán codificarse. 265 Eventos de usuario • Además de los eventos ofrecidos por GeneXus, el analista puede definir eventos creados por él, llamados eventos de usuario. • Cada evento de usuario debe asociarse a un control insertado en el form del web panel de los que soportan el OnClickEvent (botones, text blocks, imágenes, atributos) • En tiempo de ejecución, el evento de usuario ocurrirá luego de que el usuario haga clic sobre el control asociado al mismo. Casi todos los controles que aparecen en el form brindan la posibilidad de disparar un evento cuando el usuario hace clic con el mouse sobre ellos (aparecen como hipervínculos en ejecución); se consigue de dos maneras distintas: 1. Editando las propiedades del control, y definiendo un evento de usuario en la propiedad OnClickEvent 2. Dándole un nombre al control y en la sección de Eventos programando: Event nombreControl.click … Endevent Con esta última alternativa no tendremos que definir un evento de usuario, sino que estaremos programando el evento click del control. 266 Web panel "Trabajar Con Cliente” Acciones sobre el cliente seleccionado Para que el web panel con el que venimos trabajando sea un verdadero “trabajar con” se le deben agregar acciones a ser efectuadas sobre los clientes: la posibilidad de insertar un nuevo registro (nuevo cliente), el modificar uno existente, o el eliminarlo (así como también poder simplemente “visualizarlo”). Una forma de implementar esto es agregar los cuatro botones que aparecen arriba, en el form: . . . . un un un un botón botón botón botón que que que que ofrezca ofrezca ofrezca ofrezca insertar un cliente (Insert) modificar un cliente (Update) eliminar un cliente (Delete) visualizar los datos de un cliente (View) Además debemos permitir la selección de una línea de la grilla para aplicarle alguna de las acciones definidas en los botones del form. Para ello, accedemos a las propiedades de la grilla con botón derecho sobre el control grid y configuramos la propiedad AllowSelection con el valor ‘True’ como muestra la figura. Al hacerlo se nos habilitan tres propiedades más, que permiten especificar SelectionColor: el color que tendrá la línea cuando el usuario la seleccione (haciendo clic con el mouse sobre la misma); AllowHovering: la posibilidad de que cambie el color de las líneas cuando el usuario se desplaza con el mouse sobre ellas, y HoveringColor: el color que tendrá una línea cuando el mouse pasa sobre ella. Estas funcionalidades se implementan con código javaScript que se envía al Browser al ejecutar el Web Panel. En la sección de eventos del web panel, definiremos el código asociado a estos botones. Lo veremos en la página siguiente. 267 Eventos de usuario en el web panel “Trabajar Con Cliente” Event ‘Insert’ TCliente.call(‘INS’, 0) Endevent Event ‘Update’ TCliente.call(‘UPD’, ClienteId) Endevent Event ‘Delete’ TCliente.call(‘DLT’, ClienteId) Endevent En las reglas de la transacción “Cliente”: Parm(&Mode, &ClienteId ); Variable del sistema Variable de usuario ClienteId = &ClienteId if not &ClienteId.IsEmpty(); Event ‘View’ TCliente.call(‘DSP’, ClienteId) Endevent La variable &Mode es del sistema y su tipo es Character(3). Tiene la particularidad de “entender” 4 valores: • • • • ‘INS’: este valor indica ‘ejecutar la transacción en modo Insert’ ‘UPD’: este valor indica ‘ejecutar la transacción en modo Update’ ‘DLT’: este valor indica ‘ejecutar la transacción en modo Delete’ ‘DSP’: este valor indica ‘ejecutar la transacción en modo Display’ ¿Cuál es el resultado de recibir por parámetros en una transacción el modo de ejecución y la clave primaria? El permitir insertar, modificar o eliminar puntualmente una instancia y luego retornar al objeto llamador. Es por ello que en todos los eventos definidos en el Web Panel “Trabajar Con Cliente” estamos invocando a la transacción “Cliente”, pasándole dos valores por parámetro: un literal de 3 letras, que es el modo y el código de cliente correspondiente a la línea del grid que fue seleccionada (por ello necesitamos habilitar la selección de líneas del grid, mediante la propiedad AllowSelection que vimos antes). En definitiva la regla parm a definirse en la transacción "Cliente", es: parm(&Mode, &ClienteId); Como se puede observar, no recibimos el código de cliente directamente en el atributo ClienteId, sino en una variable. ¿Por qué? Si declaráramos el atributo ClienteId en vez de una variable, el valor que se recibiera en él actuaría automáticamente como filtro por igualdad. Sin embargo cuando invocamos a la transacción "Cliente" con los parámetros ‘INS’ y 0, el modo ‘INS’ indica que queremos que la transacción se ejecute en modo insert; y como en dicho caso no tenemos que enviar el código de cliente para instanciarlo, completamos el segundo parámetro con valor 0 (porque la cantidad –y el tipo de datos- de los parámetros enviados, debe coincidir con la cantidad –y el tipo de datos- de los parámetros recibidos). De modo que el valor 0 es para completar el parámetro simplemente, no para que se filtre por él tratando de instanciar un cliente de código 0. En los otros 3 casos en que se invoca a la transacción "Cliente" (con los parámetros ‘UPD’ y ClienteId ; ‘DLT’ y ClienteId ó ‘DSP’ y ClienteId respectivamente) sí se quiere filtrar por el valor del código de cliente recibido; pero basta que haya un caso en el cual se invoque a la transacción y que no sirva filtrar por el valor recibido, para que no sirva recibir el parámetro en el atributo y esa es la razón por la cuál se está recibiendo en una variable. Si la clave primaria, ClienteId es autonumerada, entonces en ese caso sí podrá recibirse en atributo. Recuerde que a partir de la inclusión de la regla parm en un objeto, éste desaparece del Developer Menú, debido a que desde el mismo no es posible el envío de parámetros. 268 Web panels - Funcionamiento • Esquema de trabajo en Internet: el servidor no sabe lo que se está haciendo en el Browser, hasta que se someta la página. Es decir, hasta que se dispare un evento (enter, de usuario, click). • Orden de disparo de eventos: es diferente si se trata de la primera carga del web panel (Get) o si ya estaba cargado cuando se dispara un evento de usuario, enter, click (Post) Es importante entender que en Internet, cuando el usuario accede a una página del servidor Web para visualizarla, el Browser baja la página al cliente. Por lo tanto, no existe forma de detectar lo que realiza el usuario: el servidor Web volverá a tener el control cuando se dispare el evento ENTER o algún evento de usuario o click. En ese momento se envía (se somete, se hace un post) el resultado al servidor para continuar con su procesamiento. Es decir, una vez que el objeto web finaliza la ejecución en el servidor, no queda en memoria. Como consecuencia, la forma en que programamos este tipo de aplicaciones presenta algunas diferencias con respecto a lo acostumbrado en ambientes no web. Es por esta razón que es importante destacar el orden en que se disparan los eventos y el momento en que las variables adquieren el valor ingresado por el usuario. El orden de ejecución de los eventos en web panels es diferente si se trata de la primera llamada al mismo (GET) o si se disparó algún evento de usuario, enter o click (POST). 269 GET: Orden de disparo de eventos • Al ejecutar un web panel por primera vez se disparan los siguientes eventos: • Start • Refresh • Load La primera vez que se ejecuta el web panel (se conoce también como el momento en que se hace el “GET” de la página) los eventos que se disparan son los siguientes y en el siguiente orden: 1. Start 2. Refresh 3. Load Luego de esto, cuando el usuario haga clic sobre un control que tenga asociado el evento Enter o uno de usuario o click se ejecutará nuevamente el web panel y el orden de disparo de los eventos será diferente, como se indica en la siguiente página. 270 POST: Orden de disparo de eventos • Resto de las ejecuciones del web panel: • Start • Lectura de variables en pantalla • Evento Enter o de usuario (submit) • Refresh • Load En el resto de las ejecuciones del web panel, que ocurren cuando se presiona un botón, o se fuerza la ejecución del evento asociado a una imagen, text block, etc. (haciendo clic sobre el control que tiene asociado el evento de usuario o Enter o click) momento que se conoce también como el “POST” de la página, los eventos se dispararán en el siguiente orden: 1. Start (nuevamente se dispara el evento Start) 2. Lectura de las variables de la pantalla. Esto se realiza porque el usuario puede haberlas modificado (por ejemplo las variables de la parte fija del web panel que están involucradas en las conditions, como en el ejemplo que se presenta arriba, donde se quieren cargar en el grid los clientes cuyo nombre contenga el string cargado por el usuario en la variable &ClienteNombre) 3. Evento Enter o click o evento de usuario (código correspondiente al evento asociado al control que se presionó y produjo el POST). 4. Refresh 5. Load En el ejemplo no necesitamos codificar nada en el evento asociado al botón Buscar. Solo lo pusimos para poder enviar al servidor la variable con el valor que ingresó el usuario y que la página se refresque cargando en el grid los clientes que cumplan con el filtro que el usuario estableció mediante esa variable. 271 Web panels - Variables • Variables: adquieren valor ingresado por el usuario luego de sometido evento (POST) • Si en un evento se usa una variable que se carga en otro evento Æ la variable debe estar en el form, y además debe estar después del control en el que se carga su valor. • Ejemplo: Event Load &cont+=1 endevent Event Enter Event Refresh &cont= 0 endevent if &cont<5 … endevent Relacionado con el orden de disparo de los eventos, es importante destacar el momento en que las variables adquieren los valores ingresados por el usuario: solamente lo harán después de presionar un botón1 (que es cuando el servidor Web tiene el control del procesamiento). Por ejemplo, cualquier Link especificado en el evento Start a otro web panel con una variable que se ingresa en el form no va a tener ningún valor cuando se haga clic sobre el Link. (Ej: control.Link = HWebPanelX.Link(&var). No se debe escribir esto en el start si la &var esta en el form, porque al momento de armarse el link no se tiene el valor de la variable) Si en un evento se usa una variable que se carga en otro evento, entonces esa variable debe estar presente en el form. Si no está en el form, la variable no tendrá valor cuando se disparen los eventos que la consultan (esto es por el “orden” en que ocurren los eventos). Además, deberá estar en el form después del control en el que se carga. Por ejemplo, si la variable se carga en el LOAD de un grid entonces la variable tiene que estar en pantalla después del grid. Ejemplo: web panel con grid que lista las facturas existentes, y queremos contar la cantidad de facturas que se listan en el grid. Para ello definimos una variable &cont que debemos incrementar cada vez que se carga una nueva línea, es decir, en el evento Load del grid. Para que la variable se cargue correctamente, deberá incluirse luego del grid, puesto que de lo contrario ya se habrá dibujado en la página, antes de que pueda ser cargada por el evento Load. Gracias a tenerla en el form, cuando el usuario presione el botón Confirm que consulta por el valor de la variable, la misma podrá tener el valor cargado antes por el Load. Recordemos que al presionar el botón Confirm se realizará un POST al servidor, y en él se dispararán Start, lectura de variables de pantalla (aquí se leerá el valor de &cont que había sido cargado antes por el evento Load), luego se disparará el evento Enter asociado al Confirm y dentro del mismo se consulta por el valor de la variable, que gracias a que fue enviada al servidor por estar en el form, tiene el valor que se había cargado antes. Luego se dispararán Refresh y Load. Observemos que aquí, cuando se dispare el Load, se incrementará la variable, por lo que deberemos resetearla antes de que se empiecen a cargar las líneas, porque de lo contrario mostrará el doble de las líneas que tenía antes. ¿Dónde resetearla? Event Refresh &cont = 0 endevent ----------------------------------------------------------------------------------------------------------------------1 O hacer clic sobre algún control del form que tenga un evento de usuario o click o Enter asociado (ya sea con la propiedad Link, o la propiedad OnClickEvent, o el evento click). 272 Ejemplo: Supongamos que tenemos un web panel donde en un sector del form se puede ingresar usuario y contraseña para loguearse al sistema. En el evento donde validamos el usuario y la contraseña (asociado a algún botón o text block), guardamos en una variable el código de usuario para poder utilizarlo en otro evento. Esto nos permitiría, por ejemplo, llamar a un objeto que permita visualizar los datos del usuario (por ejemplo un web panel de nombre “DatosCliente”, que recibirá por parámetro el identificador de cliente). En consecuencia, primero que nada, deberíamos programar lo siguiente en el evento donde validamos el usuario: Event ‘Login’ For each Where ClienteUser = &ClienteUser If ClientePassword = &ClientePassword &ClienteId = ClienteId Mensaje.Caption = ‘Bienvenido/a ’+trim(ClienteNombre) Else Mensaje.Caption = ‘La contraseña ingresada no es correcta’ Endif When none Mensaje.Caption = ‘El usuario ingresado no existe’ Endfor Endevent donde Mensaje es el nombre de un text block que dinámicamente (con la propiedad Caption) cambia de texto. Obsérvese que tenemos una tabla CLIENTE que contiene la info de usuario y password. Para realizar la llamada al web panel Datos del Cliente (DatosCliente), existen varias alternativas, una de las cuáles sería agregar un botón o una imagen con un evento click asociado (o definir un evento de usuario y asociárselo al control mediante la propiedad OnClickEvent), entonces el código seria el siguiente: Event Ver.clic // “ver” es el nombre de la imagen o botón. HDatosCliente.Call(&ClienteId) Endevent Repasemos entonces lo que ocurre: 1. En la primera ejecución se disparan los eventos: Start, Refresh y Load y podemos ingresar el usuario y password en las variables respectivas. 2. Cuando presionamos el botón o text block para validar el login, se dispara el evento Start, se leen las variables anteriores que están en pantalla, se ejecuta el código del evento Login, donde se asigna a la variable &ClienteId el código de cliente del usuario correspondiente. Luego ocurren Refresh y Load y la página se despliega en el Browser. 3. Ahora, ya estando logueados, cuando presionamos la imagen o botón con el evento click asociado, se dispara el evento Start, se leen las variables que están en pantalla, se ejecuta el evento click y ahí cuando redireccionamos al Web Panel DatosCliente, la variable &ClienteId no tiene valor alguno, ya que la misma se perdió luego de haber finalizado la ejecución del Web Panel en el punto 2. Es por esta razón que si queremos disponer del valor de la misma, deberíamos agregar la variable &ClienteId en el form y la ocultaríamos usando la propiedad Visible (por ejemplo en el evento Start). Event Start &ClienteId.Visible = 0 Endevent Entonces en este caso, cuando el Web Panel ejecute por segunda vez, se dispararán los eventos: 1. Start 2. Se leen las variables del form (en este momento se obtiene el valor de &ClienteId) 3. Se ejecuta el evento click, y por consiguiente se llama al Web Panel con el código de cliente correcto. Esto es porque no existe un concepto de “memoria local” para los web objects, por lo cual, si en un evento se usa una variable que se carga en otro evento, entonces esa variable debe estar presente en el form, de manera que, aprovechando el orden de disparo de los eventos en el POST, se obtenga el valor de la variable. 273 Definición de columnas ocultas en el grid de un web panel • Al hacer botón derecho sobre el grid y seleccionar Columns: •Editar las propiedades de la columna que se quiere ocultar: Hay veces que por motivos de presentación, no se desea incluir ciertos atributos o variables como columnas visibles de un grid, pero se necesita tener sus valores cargados en columnas ocultas. ¿Por qué motivo se puede necesitar definir una columna oculta en el grid de un web panel? Un grid siempre tiene un archivo temporal asociado. Cuando en un Web Panel se ejecuta el evento Refresh, se comienza a ejecutar la consulta a la base de datos; a continuación por cada registro leído que cumpla con las condiciones de filtro definidas, se ejecuta el evento Load y se cargan los datos de dicho registro, en el archivo temporal asociado al grid. ¿Qué datos de los registros se cargan en el archivo temporal? Es decir, ¿qué columnas contendrá el archivo temporal? Una columna por cada atributo o variable mostrado en el grid, más una columna por cada atributo o variable declarado en el grid como columna oculta. A modo de ejemplo, si en un grid hay 2 columnas visibles con los atributos ClienteNombre y ClienteSaldo y ninguna columna oculta, el archivo temporal asociado al grid contendrá 2 columnas correspondientes a los atributos ClienteNombre y ClienteSaldo, respectivamente. Si además de esas 2 columnas visibles, se declara el atributo ClienteId como columna no visible en el grid, el archivo temporal asociado contendrá 3 columnas correspondientes a los atributos ClienteNombre, ClienteSaldo y ClienteId, respectivamente. Si en el grid sólo incluimos 2 columnas visibles con los atributos ClienteNombre y ClienteSaldo, en el caso en que necesitemos en un evento de usuario conocer el valor del atributo ClienteId correspondiente al cliente de cierta línea seleccionada (para escribir alguna sentencia utilizándolo), no lo tendremos. Para conocer en un evento de usuario el valor del atributo ClienteId correspondiente a cierta línea seleccionada, tendremos que incluirlo en el grid ya sea visible o no visible, pero debe estar presente. Como ejemplo, pensemos en nuestro Web Panel “Trabajar Con Clientes”: necesitábamos una vez que el usuario seleccionaba una línea, y presionaba el botón “Update” llamar a la transacción “Cliente” enviándole como parámetro el ClienteId seleccionado. En este caso necesitamos tener el ClienteId en el archivo temporal, ya sea que esté visible en el grid o no lo esté. ¿Cómo ocultar una columna en un grid? Para ocultar una columna en un grid, debemos configurar la propiedad Visible del atributo o variable que se desea ocultar con valor ‘False’. Para ello, debemos hacer clic con el botón derecho del mouse sobre el grid y seleccionar las columnas (Columns) de la grilla; se abrirá el diálogo mostrado. Luego, habrá que posicionarse en el atributo o variable que se desee definir como columna oculta, y editar sus propiedades (Properties). Por último, se debe configurar la propiedad Visible de la columna con valor False. 274 De modo que el motivo por el cual podemos necesitar incluir un atributo o variable como columna oculta de un grid, es porque necesitemos conocer el valor de ese atributo o variable en un evento de usuario, pero no deseemos mostrarlo. Así como los eventos de usuario trabajan con los datos cargados en el archivo temporal asociado al grid, las condiciones de filtro en cambio, trabajan sobre la tabla física consultada y su tabla extendida; por lo tanto, al definir condiciones de filtro, se podrán referenciar atributos que pertenezcan a la tabla física que se consulta y su tabla extendida, sin la necesidad de que dichos atributos deban estar incluidos en el grid (ni visibles ni ocultos) ni en ninguna otra sección del web panel. Por ejemplo, piénsese en el ejemplo que ya presentamos antes: Event Load if ClienteSaldo > 10000 &tipo = 'DEUDOR' else &tipo = '' endif endevent Aquí surge la pregunta: como en este evento utilizamos el atributo ClienteSaldo para poder cargar adecuadamente la variable, ¿es necesario colocarlo oculto en el grid? La respuesta es no. En el evento Load estamos posicionados en un registro de la tabla base. Tenemos a disposición todos los atributos de esta tabla base y de la extendida, sin necesidad de cargarlos luego en el grid. 275 Comando FOR EACH LINE GeneXus nos provee el comando For each line para recorrer las líneas de un grid en un web panel: for each line [in NombreGrid] Sentencia 1 …… Sentencia N endfor in NombreGrid: solamente es necesario explicitarlo cuando hay más de un grid en el form del web panel. Sentencia 1, …, Sentencia N: sentencias a ejecutarse para cada línea recorrida del grid. 276 Comando FOR EACH LINE Ejemplo Event ‘Borrar’ for each line if &dlt = ‘S’ PBorrClientes.call(ClienteId) endif endfor Endevent A continuación, implementaremos un caso de selección múltiple, una operativa diferente a la presentada en el caso del web panel Trabajar Con Clientes, que permitía seleccionar una única línea por vez (selección simple). La operativa que pretendemos ofrecer en el web panel BorrClientes presentado arriba es la siguiente: luego de que el usuario haya ingresado un substring para filtrar los clientes y se haya cargado el grid con los clientes que cumplan dicho filtro, el usuario podrá marcar (con un clic del mouse) qué líneas (clientes) desea eliminar. En el ejemplo, hemos incluido en el grid del web panel “BorrClientes", una variable de nombre &dlt (definida como check box), además de los atributos ClienteId, ClienteNombre, PaisId, PaisNombre y ClienteDireccion. De esta forma, el usuario seleccionará el check box en los clientes que desea eliminar. A su vez, tendríamos que tener un botón “Borrar" y en el código del evento asociado a dicho botón deberíamos recorrer el grid y para cada línea seleccionada invocar a un procedimiento que haga la eliminación física de dicho cliente. A continuación incluimos el código del procedimiento BorrClientes que recibe en la regla parm el código del cliente a eliminar (ClienteId). Reglas: Parm(ClienteId); Source: for each defined by ClienteNombre Delete //se elimina el cliente recibido como parámetro Endfor 277 Variables en un grid • Por defecto todas las variables de un grid son Read-Only • For each line [in grid], evento click, OnClickEvent: modifica valor por defecto y todas las variables del grid pasan a ser de entrada. • Propiedad: Read Only para que alguna sea de salida. Cómo desplegar datos en un grid Por defecto todo atributo y variable que está dentro de un grid se despliega en ejecución como texto, es decir que es únicamente de lectura y por consiguiente no puede ser modificado. Cómo aceptar datos en un grid Es posible aceptar datos en las variables de un grid dependiendo de la programación de los eventos existentes en el objeto: 1. Si dentro de un evento del web panel se está utilizando el comando For each line, todas las variables que están dentro del grid pasan a ser de entrada. Es posible indicar en este caso cuáles son las variables que no van a poder ser modificadas (Ver más abajo). 2. Si dentro de la fila hay algún control con un evento click asociado (ó evento de usuario especificado en la propiedad OnClickEvent). Cómo indicar que una variable no puede ser modificada 1. Para indicar que el valor de una variable en un grid no puede ser modificado, debemos configurar la propiedad Read Only de la variable con valor ‘True’. Para ello, debemos hacer clic con el botón derecho del mouse sobre el grid y seleccionar las columnas (Columns) de la grilla. Luego, habrá que posicionarse en la variable que se desee definir como de sólo lectura, y editar sus propiedades (Properties). Por último, se debe configurar la propiedad Read Only de la columna con valor True. 2. Utilizando la regla Noaccept() 278 Diferentes tipos de grilla/grid • Grid estándar: datos repetitivos en formato fijo (línea, columna) • Grid Freestyle: datos repetitivos en formato libre Se dispone de dos tipos de grilla: • Grilla estándar: la que vimos hasta ahora, en Transacciones y Web Panels • Grilla Freestyle Estas grillas, agregan potencia al diseño de aplicaciones web, permitiendo al desarrollador mayor libertad a la hora del diseño. 279 Grid estándar Propiedades: Establece si el grid se cargará o no por páginas (paginado). Indica cantidad de filas por página. 0 Æ todas (no habrá paginado) Permite selección de línea del grid Los grids permiten trabajar con datos repetitivos en web panels y transacciones con form HTML. Las columnas de los grids pueden ser atributos, variables (incluyendo las de tipo bitmap), y siempre tendrán una primera fila que corresponderá a los títulos de las columnas. En ejecución, el grid será una tabla HTML. Para interiorizarse de cada una de las propiedades configurables de un grid, sugerimos acceder al Help de GeneXus. Aquí solo mencionaremos algunas como ejemplo: ControlName: Permite indicar el nombre del control. Siempre se le asigna un nombre por defecto. Class: Clase (del tema asociado al objeto) asociada al control. La propiedad Class solo se encuentra disponible si el control está en el form de un objeto que tiene un Tema asociado. BackColorStyle: Permite asignar un estilo al grid. Los estilos disponibles son: 1. None: el grid no tendrá un estilo particular, sino que tendrá el diseño del form o del control que lo contenga. 2. Header: permite especificar un color para el fondo de los títulos del grid y otro para las líneas del mismo. Las propiedades son LinesBackColor y TitleBackColor. 3. Report: permite especificar un color para el fondo de los títulos y alternar colores para las líneas pares e impares del grid. Las propiedades son LinesBackColor, LinesBackColorEven y TitleBackColor. 4. Uniform : permite especificar un único color para el fondo del grid(tanto el título como las líneas). Dependiendo del valor de la propiedad “BackColorStyle”, estarán disponibles otras propiedades adicionales relacionadas con la configuración de las líneas del grid. Rows: Esta propiedad permite al usuario indicar la cantidad de registros que va a cargar en el grid. Aplica únicamente a los grids que tienen tabla base. Si el valor de esta propiedad es 0, se despliegan tantas líneas como registros resulten de la consulta asociada. El valor por defecto de esta propiedad es 0. Collapsing: • AllowCollapsing :True: Permite colapsar el grid en ejecución • Collapsed :True: Arranca el grid colapsado. Selection: • AllowSelection: True: Especifica que es posible seleccionar una línea en la grilla. • SelectionColor: Seleccionar el color deseado al marcar la fila • AllowHovering: True: Marca la fila cuando el mouse se posiciona sobre la misma. • HoveringColor: Seleccionar el color deseado 280 Grid Freestyle • Permite “formato libre” de los registros • Tabla con registros repetitivos • No posee títulos para las columnas • Permite tener más de un tipo de control en una misma celda grid • Propiedades de diseño de tablas • Propiedades del Grid El grid Freestyle permite al usuario definir el formato de los datos a desplegar de una forma menos estructurada que el grid estándar. El grid Freestyle es básicamente una tabla a la que se le pueden insertar los atributos/variables, text blocks, imágenes, botones, web components, embedded pages, grids freestyle y/o grids que se van a mostrar posteriormente en la pantalla. Este tipo de grid no posee títulos para las columnas y además permite tener más de un tipo de control, atributo/variable en una misma celda, proporcionando de esta forma mayor libertad de diseño. Cabe destacar que el grid Freestyle posee las mismas propiedades mencionadas anteriormente para el grid estándar. En este caso para poder visualizar las propiedades hay que seleccionar la tabla donde se encuentran los atributos/variables. En el ejemplo presentado arriba queremos mostrar alguna información de los clientes. El atributo ClientePhoto se ha incluido en la transacción “Cliente” para almacenar la foto de cada cliente (es un atributo de tipo Blob). Pero no queremos mostrar la información como lo haríamos en un grid estándar, con cada elemento de información en una columna distinta del grid. Aquí queremos mostrar la foto y debajo el nombre del cliente. El comportamiento de las variables dentro de un grid Freestyle es análogo al que presentan dentro de un grid estándar, por lo tanto también quedan de ingreso si existe un For each line o For each line in <grid> dentro de algún evento, o si se asocia un evento a cualquier control de la fila. Nuevamente este comportamiento puede modificarse, agregando la regla noaccept o cambiando la propiedad Read Only. 281 Grid Freestyle Propiedades Para visualizar las propiedades de un grid Freestyle, hay que seleccionar la tabla del grid, presionar el botón derecho del mouse y seleccionar la opción ‘Properties’. Nuevamente, para interiorizarse de cada una de las propiedades configurables de un grid freestyle, sugerimos acceder al Help de GeneXus. Aquí solo mencionaremos algunas como ejemplo: Class: Permite modificar la clase de un control, ya sea en tiempo de diseño como en ejecución. La clase debe pertenecer al tema asociado al objeto que contiene el control. La propiedad Class solo se encuentra disponible si el control está en el form de un objeto que tiene un Tema asociado. BackColorStyle: Permite asignar un estilo al grid. Los estilos disponibles son los mismos que para un grid estándar (ver grid estándar) Rows: Esta propiedad permite al usuario indicar la cantidad de registros que va a cargar en el grid. Ídem a grid estándar. Columns: Esta propiedad permite al usuario indicar cuántas columnas va a tener el Freestyle grid en ejecución. Si se ingresa un valor distinto de 1, el Freestyle grid va a mostrar los registros en tantas columnas como se haya especificado en la propiedad. Si el valor de esta propiedad es 0, se despliegan tantas columnas como registros resulten de la consulta asociada. El valor por defecto de esta propiedad es 1. Esta es propia de este tipo de grids. Propiedades modificables en ejecución: En tiempo de ejecución se pueden modificar algunas propiedades, como: visible, backcolor, backColorEven, BackColorOdd, Columns, Rows y RecordCount: La propiedad RecordCount aplica únicamente a grids que tienen tabla base y retorna un número mayor o igual a cero representando la cantidad de registros de la tabla base del grid que cumplen las condiciones de selección. Puede retornar -1 si no existe navegación para la tabla base del grid. PageCount: La propiedad PageCount devuelve la cantidad de páginas del grid en base a las propiedades Rows y Columns del mismo. Al igual que la propiedad RecordCount, devuelve –1 si el grid no tiene tabla base. Para el caso de un grid estándar, también existe esta propiedad dinámica, pero toma en cuenta solo la propiedad Rows. 282 Paginado de grids en Web panels • Asignarle valor a propiedad Rows para indicar cantidad de registros a cargar por página. • Métodos: • • • • • Firstpage Nextpage Previouspage Lastpage (tabla base) Gotopage (tabla base) • Propiedades: • RecordCount (tabla base) • PageCount (tabla base) Descripción El paginado del grid aplica a grids comunes y freestyle cuya propiedad ‘Rows’ tenga un valor diferente de cero. Existen algunas diferencias relacionadas con la paginación cuando un grid tiene tabla base o no. Podemos agregar al web panel “Trabajar Con Cliente” botones de navegación para el grid (se muestran arriba) y eventos para realizar el paginado. Métodos A continuación se describen los métodos disponibles: FirstPage: El método FirstPage lleva al usuario al primer conjunto de registros devueltos. Los valores devueltos por este método son los siguientes: 0: Operación exitosa 1: No está habilitado el paginado en el grid NextPage El método NextPage lleva al usuario al siguiente conjunto de registros. Los valores devueltos por este método son los siguientes: 0: Operación exitosa 1: No está habilitado el paginado en el grid 2: Ya se encuentra en la última página PreviousPage El método PreviousPage lleva al usuario al conjunto anterior de registros. Los valores devueltos por este método son los siguientes: 0: Operación exitosa 1: No está habilitado el paginado en el grid 2: Ya se encuentra en la primera página Lastpage El método LastPage lleva al usuario al último conjunto de registros. Puede ser utilizado únicamente si el grid tiene tabla base. Los valores devueltos por este método son los siguientes: 0: Operación exitosa 1: No está habilitado el paginado en el grid 3: El grid no tiene tabla base 283 GoToPage El método GotoPage(PageNumber) permite acceder en forma directa a un determinado conjunto de registros. Puede ser utilizado únicamente si el grid tiene tabla base. Los valores devueltos por este método son los siguientes: 0: Operación exitosa 1: No está habilitado el paginado en el grid Propiedades Cada grid dispone de las siguientes propiedades que son utilizadas en la paginación: RecordCount La propiedad RecordCount aplica únicamente a grids que tienen tabla base y retorna un número mayor o igual a cero representando la cantidad de registros de la tabla base del grid que cumplen las condiciones de selección. Puede retornar -1 si no existe navegación para la tabla base del grid. PageCount La propiedad PageCount devuelve la cantidad de páginas del grid en base a las propiedades Rows y Columns del mismo. Al igual que la propiedad RecordCount, devuelve –1 si el grid no tiene tabla base. Recomendamos estudiar las consideraciones de eficiencia relacionadas con el uso de estos métodos. Se aconseja realizar un buen filtrado de datos del grid. 284 Reglas más utilizadas en Web Panels A diferencia del objeto transacción, en el cual se programa su comportamiento mediante la definición de reglas, en el objeto web panel la programación es dirigida por eventos. Son pocas las reglas para web panels, y las mismas permiten definir comportamientos puntuales (hay algunas reglas más además de las mencionadas, que se pueden consultar en el Help de GeneXus). Noaccept(&variable); En los web panels las variables que están en el form fuera de un control grid, ó que están dentro de un grid pero hay algún evento donde se utiliza el comando For each line, o se le ha asociado evento de usuario o click a algún atributo o variable del grid, son de entrada por defecto; es decir, el comportamiento por omisión es que en las mismas pueden ingresarse valores. Para definir que una variable se presente deshabilitada en un web panel, es decir, no permitiendo ingresos en la misma, una opción es definir la regla: noaccept(&variable); siendo &variable una variable definida en el objeto. La otra opción que tenemos en GeneXus para que una variable se presente deshabilitada en un web panel es configurando la propiedad Read Only de la variable con valor ‘True’. Ver sección Propiedades de la grilla. Default(&variable, valor); Asigna un valor por defecto a una variable. &variable: es una variable definida en el objeto. valor: puede ser un literal entre comillas, un número o una de las funciones Today(), Date() o SysDate(), debiendo coincidir el tipo de datos del valor con el tipo de datos de la variable. El valor por defecto se asignará a la variable al principio de la ejecución del programa. 285 Conceptos fundamentales • Web panel con a lo sumo un grid: • Con tabla base • Sin tabla base • Web panel con N grids: • Grids paralelos • Grids anidados 286 Web Panel “con tabla base” Web panel es “con tabla base” cuando a lo sumo tiene un grid y GeneXus puede determinar un for each implícito asociado a él. Para determinar si un web panel tiene tabla base y en caso afirmativo cuál será, al momento de especificarlo GeneXus analiza los atributos incluidos en: 1. form: en la parte fija 2. form: en el grid (visibles o no visibles) 3. el order del grid 4. las condiciones del grid (no en las condiciones globales) 5. los eventos fuera de comandos for each GeneXus busca la mínima tabla extendida que contenga a todos estos atributos, y la tabla base de dicha mínima tabla extendida, será la tabla base del for each implícito (es decir, la tabla que navegará el for each), se llamará tabla base del web panel. Observar que GeneXus no toma en cuenta para determinar la tabla base de un web panel: 1) los atributos recibidos por parámetro 2) los atributos mencionados en las condiciones globales del web panel Éstos actúan como filtros una vez determinada la tabla base. 287 Web panel “sin tabla base” • Un web panel “sin tabla base” es aquel que no tiene atributos en ninguno de los 5 lugares puntuados antes. • Por lo tanto GeneXus no determina un for each implícito asociado a él. Los web panels de entrada generalmente son web panels “sin tabla base” por el hecho de que suelen contener solamente variables; entonces, por no contener atributos en ninguno de los 5 lugares tenidos en cuenta por GeneXus para determinar la tabla base, son web panels “sin tabla base”. Además del caso de los web panels de entrada, existen otros casos que ameritan la definición de web panels “sin tabla base”. En la próxima página vemos la resolución de una consulta con un web panel sin tabla base. 288 Web panel “sin tabla base” Ejemplo • Mostrar para cada cliente el total facturado, pero sólo de los clientes que tienen facturas. Event Load For Each ClienteId defined by FacturaFecha &Cliente = ClienteNombre &Total =0 for Each &Total +=FacturaTotal endfor Load endfor EndEvent Dado que no mencionamos atributos en ninguno de los 5 lugares tenidos en cuenta por GeneXus para determinar la tabla base, se trata de un web panel “sin tabla base”. Por tratarse de un web panel “sin tabla base”, el evento Load se ejecuta una sóla vez; y en el mismo codificamos explícitamente los accesos con comando for each: cargamos valores en variables y para cargar líneas en el grid utilizamos el comando LOAD. Nota: Observar en este caso que todas las columnas definidas en el grid (variables: &Cliente y &Total) son exclusivamente de salida, manteniendo el comportamiento por defecto definido para las variables en un grid. Esto se debe a que no se está utilizando el comando For each line en ninguno de los eventos del web panel, ni tampoco hay definido un evento click asociado a un control del grid (ni OnClickEvent). 289 Comando LOAD • El objetivo del comando LOAD es incluir efectivamente una línea en un grid. • Una vez que se haya asignado valores a todas las variables que sean necesarias, y se desee agregar la línea al grid, deberá ejecutarse el comando LOAD. • Solamente se puede especificar el comando LOAD dentro del evento Load del grid de un web panel. Si en la codificación del evento Load definimos comandos For each y asignamos valores a las variables en las iteraciones pero no incluimos el comando LOAD, en tiempo de ejecución estaremos asignando una y otra vez valores a las variables, pero no se estarán agregado líneas en el grid (solamente quedará una línea en el grid con los últimos valores cargados en las variables). 290 Web panel “con tabla base” Ejemplo • Mostrar para cada cliente el total facturado, pero sólo de los clientes que tengan facturas. Event Load &Total =0 For Each &Total +=FacturaTotal endfor EndEvent Atributo Oculto: FacturaFecha Atributo Order: ClienteId ¡Corte de control! Atributo en el form del web panel: ClienteNombre Atributo oculto (no visible) en el grid: FacturaFecha tabla base del web panel: FACTURA Atributo order en el grid: ClienteId Al especificarse este web panel, GeneXus determinará que la tabla base del mismo es FACTURA, significando esto que el web panel tiene un for each implícito asociado, con tabla base FACTURA. Recordemos que en los web panels con tabla base, el evento Load se ejecuta N veces y es muy importante el siguiente concepto: Si en un web panel con tabla base, se incluye un comando for each en el evento Load, dicho for each se anidará al for each implícito asociado al web panel. Es decir, el for each definido en el evento Load no será un for each independiente. En el web panel del ejemplo, codificamos lo siguiente en su evento Load: - Inicialización de la variable &Total con valor cero - For each cuya tabla base será FACTURA (porque el único atributo que contiene es FacturaTotal) y dentro del mismo incrementamos la variable &Total con el total de cada factura (FacturaTotal) recorrida. De modo que como el web panel tiene tabla base FACTURA, en su evento Load definimos un for each con tabla base FACTURA también, y definimos un order indicando un criterio de agrupación, hemos implementado en el web panel con tabla base, un corte de control. En cambio, si no hubiésemos puesto el atributo FacturaFecha en el grid, el web panel seguiría teniendo tabla base, pero esta vez sería CLIENTE. En el evento Load se definió un for each con tabla base FACTURA (ya que dentro del comando for each solamente se encuentra el atributo FacturaTotal). El for each del evento Load no será un for each independiente, sino que se anidará al for each implícito asociado al web panel y estaremos implementando un join. GeneXus analizará: ¿existe algún atributo relación entre las tablas CLIENTE y FACTURA? Sí, ClienteId. Por lo tanto, GeneXus definirá el siguiente filtro automático en el for each con tabla base FACTURA: FACTURA.ClienteId = CLIENTE.ClienteId. 291 En resumen, cuando se ejecute el evento Refresh del web panel, comenzará a ejecutarse el for each implícito asociado al web panel. Y por cada cliente recorrido, justo antes de cargarse una línea en el grid con el mismo, se ejecutará el evento Load. Entonces, para ese cliente que se venía recorriendo, se ejecutará el código definido en el evento Load (es decir, se recorrerán sus facturas, sumando el total facturado del cliente). Al finalizar la ejecución del evento Load, se cargará la línea en el grid. Obsérvese que aquí no es necesario especificar comando Load para realizar la carga: se hace automáticamente por el hecho de tener una tabla asociada a este grid. En los eventos de usuario sucede algo parecido: cuando se incluye un for each en un evento de usuario, el mismo no es un for each independiente tampoco, sino que también se anidará al for each implícito asociado al web panel. GeneXus considerará qué línea del grid está seleccionada al momento de ejecutar el evento de usuario (recordar Allowselection = True), y para los datos de la misma ejecutará el evento. De modo que si estando seleccionada determinada línea con un cliente, se ejecuta un evento de usuario, y el mismo tiene un for each con tabla base FACTURA, se recorrerán las facturas del cliente de la línea seleccionada. Teniendo los conceptos relacionados al objeto web panel bien claros, el analista GeneXus podrá optar si definir un web panel “con tabla base” o “sin tabla base”. 292 Web panels “con N grids” Grids paralelos • Cuando un web panel contiene más de un grid en su form, GeneXus no determina una única tabla base asociada al web panel, sino una tabla base asociada a cada grid. • Atributos que participan en la determinación de la tabla base de cada grid: • Los incluidos en el grid (se tienen en cuenta tanto los atributos visibles como los no visibles) • Los referenciados en Order y Conditions locales al grid A diferencia de lo que sucedía para un web panel con un solo grid, en el caso de múltiples grids los atributos de la parte fija del web panel no participan en la determinación de la tabla base de ninguno de ellos, pero deberán pertenecer a la tabla extendida de alguno (para que sea posible inferir sus valores). De no respetarse esto, al especificar al web panel, se mostrará en el listado de navegación resultante, un warning advirtiendo de esta situación. Los atributos utilizados en los eventos del web panel tampoco participan en la determinación de la tabla base de ninguno de los grids. Los atributos que se incluyan en los eventos fuera de comandos for each, deberán pertenecer a la tabla extendida de alguno de los grids (al igual que los de la parte fija). 293 Web panels “con N grids” Grids paralelos - Ejemplos Una tabla base por grid No busca ni establece relaciones entre ellas Ejemplo: Dado que el web panel “Ver Proveedores y Clientes” tiene más de un grid en su form, GeneXus no determinará una tabla base asociada al web panel, sino que determinará una tabla base para cada grid. En este ejemplo, no hay definidos ni Order ni Conditions para ninguno de los grids, por lo tanto GeneXus sólo tendrá en cuenta los atributos incluidos en cada grid para determinar sus tablas bases. La tabla base del grid que se encuentra arriba en el form será: PROVEEDOR y la tabla base del grid que se encuentra abajo en el form será: CLIENTE. Es importante resaltar que GeneXus determina la tabla base de cada grid pero no busca ni establece relaciones entre las mismas. Al igual que en el web panel “Ver Proveedores y Clientes”, en el web panel “Ver Clientes y Facturas”, GeneXus determinará la tabla base del primer grid (que será CLIENTE) y la tabla base del segundo grid (que será FACTURA), pero no analizará si hay atributos en común entre ellas, y por ende no definirá filtros automáticos. Es decir que los grids tendrán asociadas navegaciones independientes o paralelas. Si bien GeneXus no establece relaciones entre las tablas bases de los grids, el analista podrá definirlas explícitamente. Primero estudiaremos los eventos en web panels con más de un grid, y a continuación veremos cómo definir cargas relacionadas. 294 Web panels “con N grids” Grids paralelos – Eventos y carga • • • • • Un Refresh global No se relacionan las cargas Refresh independiente de grids. Evento Load de cada grid Secuencia de Carga: Refresh <Grid Control Name1>.Refresh <Grid Control Name1>.Load <Grid Control Name1>.Load <Grid Control Name1>.Load N veces si GridControlName1 tiene tabla base. Sino 1. <Grid Control Name2>.Refresh <Grid Control Name2>.Load <Grid Control Name2>.Load <Grid Control Name2>.Load N veces si GridControlName2 tiene tabla base. Sino 1. En web panels con más de un grid, existe un evento Refresh global y un evento Refresh particular para cada grid. El evento Load, no existe global sino sólo a nivel de cada grid. Los eventos Refresh y Load a nivel de grids, deben referenciar al grid usando la siguiente nomenclatura: Event <Grid Control Name>.<Refresh | Load> .... EndEvent Por ejemplo, si en el web panel “Ver Proveedores y Clientes”, los nombres de los grids son SuppliersGrd y ClientesGrd respectivamente, para codificar los eventos Refresh y Load a nivel de los grids, la sintaxis deberá ser: Event SuppliersGrd.Refresh .... EndEvent Event SuppliersGrd.Load .... EndEvent Event ClientesGrd.Refresh .... EndEvent Event ClientesGrd.Load .... EndEvent Además de estos eventos a nivel de los grids, estará el evento Refresh global: Event Refresh .... EndEvent La carga de los grids en un web panel se realiza para cada grid de forma independiente. Es decir, aún si los datos que se muestran en ambos grids están relacionados, el especificador no relaciona las cargas. La carga asociada a los grids de un web panel incluye el evento Refresh, o sea que la secuencia de carga de un objeto con 2 grids es como se muestra arriba. La ejecución del método Refresh de cualquier grid solo se dispara par refrescar dicho grid. El orden en que se cargan los grids es como aparecen en el form: de arriba hacia abajo y de izquierda a derecha. De esa manera, cada uno de los grids se cargará con los datos correspondientes. 295 Web panels “con N grids” Grids paralelos - Comandos • Load: La sintaxis sigue siendo Load, pero debe estar incluido dentro del evento load asociado al grid que se está queriendo cargar. Su uso es análogo al caso de un grid (sin tabla base). – Event Grid1.Load .... Load Endevent • For each line: Debe incluir una referencia al grid de la siguiente forma: – For each line IN <Grid Control Name> El comando LOAD mantiene la misma sintaxis en Web Panels con más de un grid. Se debe incluir al mismo para hacer cargas de grids sin tabla base, dentro del evento Load de un grid. 296 Web panels “con N grids” Grids paralelos - Cargas Relacionadas • Se requiere la implementación de un Web Panel que muestre en un grid todos los países (GrdPaises), y cada vez que el usuario seleccione un país, que se carguen sus clientes en un segundo grid (GrdClientes). SOLUCIÓN 297 Web panels “con N grids” Múltiples grids - Cargas Relacionadas AllowSelection = True Event Enter &PaisId = PaisId EndEvent // Enter AMBOS GRIDS CON TABLA BASE En la solución que se presenta, ambos grids han sido definidos “con tabla base”, así que cada uno de ellos tiene un for each ímplicito asociado: • GrdPaises tiene un for each implícito asociado que navega la tabla PAIS. • GrdClientes tiene un for each implícito asociado que navega la tabla CLIENTE. Debemos habilitar la selección de línea por parte del usuario para el grid de países (propiedad AllowSelection del grid GrdPaises). Cuando el usuario la seleccione, presionará el botón “Ver Clientes” para que se desplieguen en el grid inferior todos los clientes del país seleccionado. Para ello necesitamos guardar en una variable el país seleccionado, para que luego, cuando se haga la carga del grid de los clientes, puedan éstos filtrarse mostrando solo los que correspondan al valor almacenado en esa variable. Es decir, en el evento asociado al botón, asignaremos a la variable &PaisId el valor del país actual, es decir, del de la línea seleccionada por el usuario. Recordemos que cuando se presione este botón, se disparará el evento Start, luego se leerán las variables del form (en este caso no hay), luego se disparará el evento asociado al botón (allí se le dará valor a la variable) y luego se dispararán el evento refresh general y a continuación los eventos refresh y load para cargar nuevamente el grid de países, e inmediatamente el refresh y load para cargar los clientes (y aquí se aplicará el filtro asociado). Observar que no necesitamos colocar la variable &ClienteId en el form, puesto que es cargada y utilizada en la misma ejecución en el servidor, por lo que no pierde su valor. Existen otras soluciones posibles para implementar la carga relacionada en web panels con múltiples grids que veremos a continuación. 298 Solución Nro. 2: Grid Grdcountries “con tabla base” y GrdClientes “sin tabla base” En esta segunda solución, el grid GrdPaises ha sido definido “con tabla base”, así que tiene un for each ímplicito asociado al mismo, que navega la tabla PAIS. Debemos habilitar la selección de línea por parte del usuario sobre este grid, a través de la propiedad AllowSelection. Una vez que el usuario se posiciona en una línea y presiona el botón “Ver Clientes” se debe refrescar el grid GrdClientes con los clientes que pertenezcan a ese país. Al igual que antes, en el evento asociado al botón (en nuestro caso es el enter), debemos darle valor a la variable para que luego pueda ser utilizada para filtrar. Event Enter &PaisId = PaisId endevent El grid GrdClientes fue definido “sin tabla base” asociada, por lo cual debemos programar a mano la carga del grid en el Evento Load. Event GrdClientes.Load For each where PaisId=&PaisId &ClienteId=ClienteId &ClienteNombre = ClienteNombre Load endfor Endevent Como el grid de clientes (GrdClientes) es “sin tabla base”; cada vez que se ejecute Refresh para el grid GrdClientes, a continuación se ejecutará su evento Load una sola vez. Por lo tanto, programamos en el evento GrdClientes.Load un for each con tabla base CLIENTE, filtrando los clientes del país que habíamos cargado en una variable, y agregamos explícitamente los clientes en el grid (asignando a las variables &ClienteId y &ClienteNombre los valores de los atributos ClienteId y &ClienteNombre respectivamente y ejecutando el comando Load a continuación para efectuar la carga de cada línea). Recordemos que cuando el usuario habiendo seleccionado un país en el grid correspondiente, presione el botón “Ver Clientes” se realizará un post al servidor, donde se ejecutará el evento Start, luego se leerán las variables de pantalla, se ejecutará el código asociado al botón (evento Enter), donde la variable para filtrar es cargada, y a continuación se dispara el evento Refresh general, y luego el Refresh seguido de N ocurrencias del evento Load del grid de países (1 por cada país a ser cargado) y finalmente el evento Refresh del grid de clientes, seguido de un evento Load para ese grid (dentro del cuál se cargan las líneas con el comando Load). 299 Solución Nro. 3: Ambos grids “sin tabla base” En esta tercera solución ambos grids han sido definidos “sin tabla base”, por lo cual el evento Load de cada grid se ejecutará una sóla vez. Event GrdPaises.Load For each &PaisId=PaisId &PaisNombre=PaisNombre Load Endfor Endevent Event GrdClientes.Load For each where PaisId=&PaisIdActual &ClienteId=ClienteId &ClienteNombre = ClienteNombre Load endfor Endevent En el evento Load correspondiente al grid GrdPaises, programamos explícitamente con comando for each y comando Load, que se carguen todos los países de la tabla PAIS. Luego codificamos el evento Enter asociado al botón “Ver Clientes”: Event Enter &PaisIdActual = &PaisId Endevent En tiempo de ejecución, estas 3 soluciones vistas se comportarán igual. Como se ha mencionado anteriormente, si se incorporan bien los conceptos teóricos vistos, el analista GeneXus podrá optar al definir un web panel, si trabajar “con tabla base”, “sin tabla base” o combinando ambas cosas. 300 Web panels “con N grids” Grids paralelos - Consideraciones • Acerca de condiciones de filtro • Es posible especificar condiciones de filtro tanto a nivel global como a nivel de cada grid. • Para cada grid se tendrán en cuenta las condiciones globales y las condiciones locales (es decir: condiciones globales and condiciones locales). • Las globales nunca participan de la determinación de la tabla base • No es posible nombrar a un atributo o variable de un grid • Ejemplo: GrdPaises.PaisId / GrdClientes.PaisId • Sí es posible referirse a PaisId, codificar sus propiedades, eventos y métodos • Igualmente no se recomienda tener el mismo atributo / variable en más de un grid, ya que las codificaciones afectarían a todos Si por ejemplo el atributo PaisId se agregara en más de un grid y se codificara: PaisId.Visible=0, el atributo PaisId quedaría invisible en todos los grids. 301 Web panels “con N grids” Grids Anidados • Varios niveles de anidación • Anidaciones paralelas • Ej: Paises y Clientes ejecución • Para profundizar en este tema dirigirse al curso de Desarrollo de aplicaciones para Internet con GeneXus Es posible definir grids “anidados” en un web panel. Los grids anidados consisten en un grid Freestyle al que se puede insertar dentro de una celda otro grid estándar u otro Freestyle. Por ejemplo, se quiere tener un web panel que muestre los clientes, pero indentados por país, como se muestra en la imagen en ejecución arriba a la derecha. Para ello se define un grid freestyle con el país y dentro de éste se inserta otro grid, en este caso estándar, con los clientes. Puede haber grids anidados de varios niveles y puede haber también paralelos. Puede decirse que se está definiendo un árbol en donde cada nodo es un grid. Cada grid puede ser un freestyle o un grid estándar, aunque si es estándar no puede tener ninguno anidado. Los grids estándar sólo pueden ser hojas del árbol de anidación. No se ahondará en el tema en el presente curso. Podrá hacerlo en el curso de Desarrollo de aplicaciones para Internet con GeneXus. 302 Web panels • Tipos de Web panels • Component • Master Page • Web Page • Propiedad Type Los objetos web pueden ser definidos con tres tipos diferentes, configurable en la propiedad Type del objeto. Para un web panel podrá tomar uno de los valores: •Component: (transacción ó web panel, que a partir de aquí podrá ser incluido en otro web object) •Master Page •Web Page (es decir, el objeto será una transacción ó web panel tal como hemos trabajado hasta el momento) El tipo de web panel ‘Component’ se analiza en detalle en el curso Desarrollo de Aplicaciones para Internet con GeneXus. A continuación introduciremos el Web Panel tipo “Master Page” y su utilización. 303 Master Pages HEADER CONTENT M ENU Tener un look&feel consistente es hoy en día un deber de toda aplicación Web. Crear y mantener cada página de una aplicación Web asegurando la consistencia con el resto del sitio toma gran tiempo de programación. En el ejemplo presentado arriba, hemos capturado una pantalla del sitio de Sony. Navegando entre las distintas pantallas, nos hemos encontrado que todas ellas tienen un header común, así como un menú a la izquierda de cada página. Ambas cosas pueden ser visualizadas en la pantalla capturada arriba. Lo que va variando a medida que uno va navegando por las distintas páginas es lo que aparece a la derecha, y que es el contenido específico de cada página. ¿Cómo implementar un sitio de estas características? Con el conocimiento que tenemos hasta el momento, tendríamos que repetir la parte del Layout común a todas las páginas del sitio, así como el comportamiento común, en cada web panel que implementa cada una de esas páginas. Eso introduce dos problemas fundamentales: si hubiera que realizar alguna modificación a esas partes comunes a todas las páginas, habrá que ir página por página a realizarlo. Y relacionado con esto, la posibilidad de olvidarnos de hacerlo en alguna página, o introducir alguna variación en la misma, degradará la consistencia del sitio. Las Master Pages proveen una forma de centralizar el layout y el comportamiento común en un solo objeto y reutilizarlo en todo otro objeto sin tener que programar. Esto significa que la modificación de alguna parte del layout o del comportamiento común es tan fácil como modificarla en un único objeto y ¡listo!. Se creará un web panel categorizado como “Master Page” con todo lo que sea el Layout y comportamiento común a todas las páginas del sitio, y en el mismo se dejará un espacio para cargar en cada oportunidad la página que corresponda (el contenido variable del sitio). Las páginas web que implementan el contenido variable, se implementan como Web Panels o Web Transactions comunes y corrientes (es decir de tipo “Web Page”, ver página anterior), y se asocian a la Master Page, de manera que cada vez que se ejecuten, se carguen con ese “contexto”. 304 Master Pages • Propiedad Type = ‘Master Page’ • Permiten definir en un único lugar el layout y comportamiento común a todas las páginas del sitio (especifican el marco o contexto de toda página) Header Menú Marco, contexto de todas las páginas del sitio Lugar donde las páginas individuales serán cargadas. Master Pages Se crea entonces un objeto Web Panel y se le configura la propiedad Type con el valor ‘Master Page’. En una misma base de conocimiento se pueden definir tantas Master Pages como se desee. Una vez que exista al menos una Master Page en la base de conocimiento, puede ser referenciada desde cualquier web panel o web transaction, en la propiedad MasterPage de estos objetos (que por defecto tiene el valor “(none)”). El efecto de hacer esto será que al ejecutar estos objetos, se ejecutarán con la master page asociada, es decir, se cargará la master page, y en el “hueco” es donde se cargará la página individual. Se profundiza en Master Pages, Web Components, Embedded Pages, en el curso Desarrollo de Aplicaciones para Internet con GeneXus. 305