Validaciones en las filas seleccionadas de un Tabular Form- Apex

Esto que puede ser tan simple me tomo casi 3 horas saber como hacerlo, el ejemplo sera para validar al momento de eliminar en Apex 4.1.1 aunque puede funcionar en otras versiones de Apex.

Los archivos para correr el ejemplo pueden ser descargados aquí. El .rar incluye script de creación de BD y la aplicación. La base de datos solo contiene 2 tablas, una de artistas y otra de canciones. en este ejemplo validaremos que no se pueda eliminar un artista si tiene canciones asociadas.

Lo primero es identificar el id de cada columna, para esto buscamos el id de cada columna, generalmente corresponde con el orden en el que están las columnas, en el reporte.

En este caso las columnas y sus ID son:
  • [row selector]: f01
  • ID_ARTIST: f02
  • ID_ARTIST_ROW_DISPLAY: f03
  • NAME: f04

Si quieren estar seguros, busquen en el código fuente 'f0x', remplazando x por algún número y así podrán saber el id de cada columna.

Creamos una validación a nivel de página, de tipo pl/sql - Función retornando texto de error. y luego colocamos el código en pl/sql que ejecute la validación que queramos, en este caso verificar que el id del artista que se quiere eliminar no este asociado con ninguna canción. Finalmente colocamos la condición para que se ejecute la validación, en este caso es cuando se oprima el botón 'Delete'. (Observa los pasos gráficamente aquí)

Este es el código que usare en este ejemplo, más adelante explicare los bloques importantes.
DECLARE

TYPE ArrNumber IS TABLE OF NUMBER;
ID_ASOCIATED arrNumber;

v_rowno NUMBER; -- Rown number 
rownumber char(4); -- ID of current Row  
errorRows varchar2(32000) :=','; -- rows ID with errors
error varchar2(32000); -- error Message
BEGIN

-- Find the ID of all asociated data
  select ID_ARTIST
  bulk collect into ID_ASOCIATED
  from SONG
  order by  ID_ARTIST;

for i in 1..apex_application.g_f01.count  
 loop  
  -- Get the number of the row  
  v_rowno := apex_application.g_f01(i);
  
  for C in 1..ID_ASOCIATED.COUNT LOOP
 
 EXIT WHEN ID_ASOCIATED(C) > apex_application.g_f02(v_rowno);
 -- IF the selected row is asociated to something
 if (ID_ASOCIATED(C) = apex_application.g_f02(v_rowno)) then
  
  rownumber := to_char(v_rowno,'FM0000');
  errorRows:= errorRows||','||''''||rownumber||'''';
  
  -- Add error row message  
  error:= error||chr(10)||'
  • (fila '||v_rowno||')
  • '; END IF; END LOOP; END LOOP; errorRows := ltrim(errorRows,','); if( error is not null ) then -- Print the variable to be send to the .js and return error message. return 'Los siguientes elementos están asociados a algún registro en la base de datos y no pueden ser eliminados.
      '||error||'
    ' || ''; end if; end;
    Explicación del código
    Lineas Funcionalidad
    12-16 Obtenemos todos los ID que están asociados a una tabla y los ordenamos, Estos ID estaran almacenados en una colección
    18 Loop para recorrer las filas seleccionadas.
    21 Obtenemos el número de la columna ya que apex_application.g_f01 es un array de las filas seleccionadas, por lo que el número de la columna no coincidira con el valor de i.
    23 Loop para recorrer los ID asociados.
    25 No es necesario recorrer todo el arreglo por que está ordenado y si el ID que estamos evaluando es menor que el que estamos evaluando, salimos del LOOP.
    29 se pasa el número de la fila a un formato en el que se rellena con 4 ceros, es decir, si la fila es la número 1, el resultado seria 0001, esto es para determinar el id de la fila en el que surgió el error.
    30 Se colocan los id de las columnas en la siguiente forma 0001,0004,0006 para al final ser concatenados y crear un arreglo en JavaScript
    33 se van agregando las filas en las que se genero el error con el texto "fila xx" en donde xx es el número de la fila, este texto es un link el cual ejecutara una función de Javascript que seleccionara el ítem que se indique. el f04 se debe cambiar por el id de la columna a la que se quiere enviar al usuario.
    38 Eliminamos las comas iniciales, esto evita tener un IF que evalue si esta vacio o no y le coloque una coma dependiendo de eso.
    41 Retornamos el mensaje de error con la lista de links hacia las filas con el error y los valores de erroRows concatenado con otras cosas para que se cree un arreglo con los id de las filas que tuvieron error

    Todo lo relacionado con el JavaScript es solo para darle más estilo y hacerlo más bonito, si quieren pueden evitar esa parte y ya habrán acabado :). Pero como Apex 4.1.1 muestra los errores todos bonitos, entonces toca continuar para que no quede tan diferente. La idea de crear la variable con el id de las filas, es poder enviar estos ID's a una función que se encargara de cambiar la clase de uno de los campos de cada fila en el tabular form para que se resalte de rojo. La función es la siguiente.
    function setErrorClass(column, rows){
    for(var i=0;i< rows.length;i++){ 
      document.getElementById('f'+column+'_'+rows[i]).setAttribute("class", "apex-tabular-form-error");
         }
    }
    
    Guardamos este script en un archivo .js, lo cargamos a APEX y luego lo importamos a la aplicación o la página. (Si no saben como hacerlo en este post lo explico, no es especifico de eso, pero ahí lo explico, ademas tal vez les interese el tema :P. Restringir Tamaño de entrada en campos de un Tabular Form ).

    Ahora lo único que falta es llamar la función, eso lo hacemos con este otro script, el cual debemos colocar en el pié de página. ¿Por qué en el pié de página? Por que nuestra función cambiara la clase de los objetos que se encuentran en las filas que generaron error, por lo tanto deben haber sido creados y si hacemos esto en el header, tendremos un bello y desagradable error de que el objeto es null.
    
    
    Los parámetros que le enviamos son el id de la colma del ítem que queremos resaltar y el array con los id de las filas que generaron error. Pero antes validamos que esta variable exista. Y listo, con esto tendremos una validación que resalta los campos tal cual como lo hace Apex :D o bueno, parecido :P. En la imagen se ve como se genero error al intentar eliminar todos los registros, pero 'Perfume' y 'Nelly Furtado' tienen canciones asociadas a ellas.



    Y ahora a Celebrar :D.


    Fuentes
    APEX Tabular Form with [row selector]: How to set value of column in selected rows on submit: De aquí saque como recorrer las filas seleccionadas.

    Oracle SQL for padding leading zeros: Como transformar un número a un formato con ceros iniciales.

    Change HTML class attribute using javascript: Como cambiar la clase de un objeto usando JavaScript.

    The typeof operator: Como determinar si una variable existe o no en JavaScript.



    Y ahora el vídeo :P. Es mi Favorito de Perfume, de hecho se me hace extraño no haberlo puesto antes :o pero aquí esta para que lo disfruten mientras continúan con sus labores:)


    Comments

    Popular posts from this blog

    View PDF File on APEX (Simple approach)

    Set Custom APP Icon on APEX

    ID Basado en trigger y secuencia para todas las tablas - Oracle