Skip to main content

Command Palette

Search for a command to run...

Pequeños grandes detalles en APEX: el Combo Box y el espíritu de #JoelKallmanDay

Published
10 min read
Pequeños grandes detalles en APEX: el Combo Box y el espíritu de #JoelKallmanDay
J

I am a technology professional with about a decade of experience in software development, specialising in Oracle APEX. My career began in telecommunications engineering, but my passion for technology and software development led me to transition into this field. Since then, I have been deeply involved in leading teams and driving digital transformation across various projects. As a part of my daily tasks, I focus on fostering collaboration, efficiency, and technical excellence, ensuring that the projects where I'm involved embrace digital advancements effectively. I take great pride in sharing my knowledge and experience, whether through mentorship, conferences, or engaging with the tech community.

Para quienes llevamos ya algunos años formando parte de esta maravillosa comunidad #orclAPEX, un día como hoy no puede pasar desapercibido.

El 15 de octubre comenzó hace tiempo como una jornada dedicada a celebrar la comunidad APEX, con eventos, charlas y contenido compartido en todo el mundo. Sin embargo, tras el fallecimiento de Joel R. Kallman, co-creador de Oracle APEX, en 2021, la comunidad decidió dedicarle esta fecha y convertirla en un homenaje permanente a su legado.

Siempre resulta entrañable recordar anécdotas sobre quién fue Joel y cómo se relacionaba con la comunidad. Coincido plenamente con la mayoría de quienes destacan su espíritu incansable de evangelización sobre APEX y su capacidad para inspirar a todo tipo de público, técnico o de negocio.

Recuerdo especialmente una anécdota divertida en una de las últimas conferencias donde coincidimos: la del grupo de usuarios de Reino Unido (UKOUG). Fue justo antes de la pandemia, y recuerdo que vino acompañado de Shakeeb Rahman. Durante su presentación, Joel tuvo la genial idea de mostrar un mapa interactivo que, partiendo de una vista del planeta, hacía zoom in hasta su propia casa para ilustrar “de dónde venía”.

Entre risas y comentarios, aquello se convirtió en tendencia improvisada, y recuerdo a Shakeeb en su charla posterior intentando recrear el efecto haciendo zoom a toda velocidad en el navegador, lo que provocó aún más carcajadas entre los presentes.

Elemento Combo box

Si pienso en el impacto que personas como Joel Kallman y una tecnología como Oracle APEX han tenido en mi carrera, destacaría algo que siempre me ha fascinado: la capacidad de la comunidad para influir en la evolución del producto.

A primera vista, podríamos pensar en APEX como una herramienta centrada en la captura de datos y el reporting, muy orientada al entorno corporativo. Pero, con el tiempo, APEX ha demostrado que también es un entorno ideal para crear experiencias de usuario cuidadas hasta el detalle, donde cada pequeño componente puede marcar la diferencia.

En esa línea, el Combo Box Item, introducido en la versión 23.2, es un ejemplo perfecto de cómo la plataforma sigue refinándose para mejorar la interacción con el usuario sin perder su sencillez, siguiendo con un legado cuya impronta nos es familiar a muchos de nosotros.

Este tipo de elemento representa una evolución natural del clásico Select List o Lista de Valores (LOV). A primera vista pueden parecer similares, pero el Combo Box aporta varias mejoras interesantes que lo hacen más flexible y cómodo de usar.

A diferencia de las listas de valores (LOVs) tradicionales o las Popup LOVs, el Combo Box permite no solo seleccionar un valor existente, sino también escribir valores nuevos no incluidos en la lista, lo que le da un comportamiento mucho más dinámico y adaptable a distintos escenarios.

Este nuevo tipo de elemento dispone de dos modos diferenciados:

  • Combo Box One → permite una única selección de entre los valores disponibles.

  • Combo Box Many → admite múltiples valores, que se muestran como pequeñas “etiquetas” (chips) dentro del propio campo.

Su configuración resulta muy sencilla, y permite aprovechar tanto listas estáticas como LOVs dinámicas basadas en consultas SQL.

Por ejemplo, una lista de empleados podría configurarse con una consulta como esta:

SELECT ename   as d
     , empno   as r
FROM emp
order by 1

De esta forma, los usuarios pueden comenzar a escribir y APEX filtrará los resultados en tiempo real, mostrando solo los que coinciden con el texto introducido.

Para más detalles, se puede consultar la documentación oficial del Combo Box en Oracle APEX, donde se explican todas las opciones y propiedades disponibles.

Y como el movimiento se demuestra andando, vamos a ver unos ejemplos de este componente en acción.

Como punto de partida, usaremos una sencilla aplicación de ejemplo de Empleados / Departamentos, que ya hemos utilizado en otras ocasiones.

Combobox One

El primer paso puede ser, simplemente, sustituir una sencilla Lista de valores (Select List) por este otro elemento Combo Box.

Si disponéis de la aplicación EMP/DEPT de partida, podemos navegar al formulario de edición de empleados (en mi caso, la página 3).

Para convertir nuestra Select List en un Combobox, basta con cambiar el tipo del elemento P3_MGR y ejecutar la aplicación para ver qué ocurre:

Ups! Parece que no era tan sencillo…

Pero, en realidad, si leemos la documentación, se trata de un error esperado: cuando un elemento Combobox utiliza como fuente de datos una consulta con valores Display y Return, necesita apoyarse en otro elemento que almacene las entradas manuales. Para resolverlo, creamos un elemento auxiliar con las siguientes características:

Identification > Name: P3_MGR_ME
Identification > Type: Hidden

Settings > Value Protected: Disabled

Una vez creado, regresamos al elemento original y en el atributo Settings > Manual Entries Item seleccionamos el elemento que acabamos de crear (P3_MGR_ME).

Si ahora ejecutamos nuestro formulario, ahora vemos que todo funciona correctamente.

Para cerrar este ejemplo, estaría bien destacar algunos detalles:

  • Este elemento incorpora mejoras de interfaz por defecto, como la posibilidad de limpiar el valor del item con un solo clic.

  • Al escribir, podemos filtrar dinámicamente el contenido de la lista, haciendo el formulario más ágil e intuitivo.

  • Además, se pueden ajustar opciones similares a las de las Popup LOVs: número mínimo de caracteres para iniciar la búsqueda, número máximo de resultados mostrados, etc.

Estos aspectos se amplían en los siguientes epígrafes, donde exploraremos más posibilidades del Combo Box.

Combobox Many

Si el modo One ya aporta flexibilidad al permitir búsquedas dinámicas, el modo Combo Box Many va un paso más allá al permitir seleccionar varios valores a la vez, que se muestran como pequeñas chips dentro del propio campo.

Su uso es especialmente útil cuando queremos asociar múltiples elementos relacionados —por ejemplo, asignar varios proyectos a un empleado, o varios responsables a una tarea— sin recurrir a formularios adicionales ni a componentes personalizados.

Para probarlo, podemos crear un nuevo elemento en la misma página de empleados con las siguientes propiedades básicas:

Identification > Name: P3_SKILLS
Identification > Type: Combo Box

Settings > Combo Box Mode: Many

Multiple Values > Type: Delimited List
Multiple Values > Separator: :

List of Values > Type: Static

Y añadimos algunas entradas estáticas representando habilidades comunes (rellenando Display y Return value):

SQL;SQL
PL/SQL;PLSQL
JavaScript;JAVASCRIPT
Python;PYTHON
UX Design;UX_DESIGN
Data Modeling;DATA_MODELING
API Integration;API_INTEGRATION

De nuevo, al contar con una lista - en este caso estática - con columnas de Display y Return value, debemos crear un Item oculto de apoyo para el campo Manual Entries. Si lo creamos del mismo modo que en el ejemplo anterior, con el nombre P3_SKILLS_ME, ahora podemos ejecutar la aplicación, y veremos cómo el campo permite seleccionar múltiples habilidades que se apilan visualmente en forma de chips, con la opción de eliminarlas individualmente:

Creación de entradas manuales

Este punto es un poco más avanzado, por lo que iremos paso a paso. Para mostrar como persistir entradas manuales, vamos a tener que realizar una pequeña modificación a nuestro modelo de base de datos: para evitar modificar las tablas de empleados y departamentos, vamos a crear dos tablas nuevas que simulen la lógica que hemos introducido en el ejemplo anterior y permitir seleccionar múltiples habilidades para un empleado. Vamos a crear dos tablas nuevas:

  • Tabla de habilidades (SKILLS)

  • Tabla intermedia de empleado-habilidades(EMP_SKILLS)

Para ello, solo tenemos que correr el siguiente script:

-- Catálogo de habilidades
create table skills (
  skill_id   number generated always as identity primary key,
  skill_name varchar2(100) not null,
  constraint uk_skills_name unique (skill_name)
);


-- Relación M:N empleado–habilidad
create table emp_skills (
  empno    number not null references emp(empno) on delete cascade,
  skill_id number not null references skills(skill_id),
  constraint emp_skills_pk primary key (empno, skill_id)
);

-- Insertamos algunos valores iniciales
insert into skills (skill_name)
  select column_value
  from table(apex_string.split(
    'SQL:PL/SQL:JavaScript:Python:UX Design:Data Modeling:API Integration', ':'
  ));

commit;

Tras ejecutar nuestro script, podemos crear una Lista de valores dinámica a partir del contenido de la tabla SKILLS, para alimentar correctamente el Combobox del ejemplo, en lugar de depender de la lista de valores estática del ejemplo anterior.

Para permitir que los usuarios añadan nuevas habilidades directamente desde el Combo Box, añadiremos un botón y un proceso de página que capture esas entradas, las inserte en la tabla SKILLS (si no existen) y las asocie al empleado actual.

🔘 Botón Creamos el botón con los siguientes atributos, junto al item Combobox, en la misma línea del formulario:

Identification > Button Name: ADD_NEW_SKILLS
Layout > Start New Row: No
Layout > Column Span: 1
Appearance > Button Template: Icon
Appearance > Icon: fa-plus
Behaviour > Action: Submit Page

Además, aplicamos un poco de estilo para que se vea correctamente alineado y, en sus atributos de apariencia, elegimos los siguientes valores en sus correspondientes propiedades:

Size: Large
Spacing Top: Large

⚙️ Proceso PL/SQL

Creamos ahora un nuevo proceso de página, con los siguientes atributos:

Identification > Name: Add new skills
Identification > Type: Execute Code
Source > Language: PL/SQL
Source > PL/SQL Code:
declare
  l_skill_id  skills.skill_id%type;

  procedure upsert_skill(p_name in varchar2, p_skill_id out number) is
  begin
    begin
      insert into skills (skill_name)
      values (p_name)
      returning skill_id into p_skill_id;
    exception
      when dup_val_on_index then
        select skill_id into p_skill_id
        from skills
        where skill_name = p_name;
    end;
  end;

  procedure append_to_item(p_id in number) is
  begin
    if :P3_SKILLS is null then
      :P3_SKILLS := p_id;
    else
      if instr(':'||:P3_SKILLS||':', ':'||p_id||':') = 0 then
        :P3_SKILLS := :P3_SKILLS || ':' || p_id;
      end if;
    end if;
  end;

begin
  for c in (
    select trim(regexp_replace(column_value, '\\s+', ' ')) as skill_name
    from table(apex_string.split(:P3_SKILLS_ME, ':'))
    where trim(column_value) is not null
  ) loop
    upsert_skill(c.skill_name, l_skill_id);
    append_to_item(l_skill_id);

    if :P3_EMPNO is not null then
      begin
        insert into emp_skills (empno, skill_id)
        values (:P3_EMPNO, l_skill_id);
      exception
        when dup_val_on_index then null;
      end;
    end if;
  end loop;

  :P3_SKILLS_ME := null;
end;
Success Message > Success Message: New skill(s) added!
Server-side Condition > When Button Pressed: ADD_NEW_SKILLS

Con este proceso, las nuevas habilidades que se escriban en el Combo Box se insertarán automáticamente en la tabla SKILLS y, si hay un empleado en edición, también quedarán asociadas a él en EMP_SKILLS.

Template Directives

Por último, me gustaría enlazar con el post anterior. En este componente, se pueden aplicar template directives en el atributo Value HTML Expression, lo cual abre la puerta a multitud de mejoras adicionales a nivel de UI/UX.

Para ver como podemos sacar partido de este atributo, vamos a volver al primer ejemplo, Combobox One. Navegamos a Shared components para añadir algunas columnas adicionales a la lista de valores que utilizamos, para incluir los campos que vamos a utilizar en este formateo: EMPNO, ENAME y JOB. Para ello, la única modificación que habrá que hacer será agregar JOB en la sección Additional Display Columns - EMPNO y ENAME ya estarán disponibles.

Ahora, volvemos a nuestro formulario, y en el atributo Settings > Value HTML Expressión del item P3_MGR, aplicamos el siguiente código:

<style>
.jk-combo-row{
  display:flex;align-items:center;gap:8px;
  padding:6px 10px 7px 10px;border-radius:10px;
  background: var(--ut-component-background-color);
  border: var(--ut-component-border-width) solid var(--ut-component-border-color);
  box-shadow: 0 1px 0 var(--ut-component-inner-border-color) inset;
  transition: background .15s ease, border-color .15s ease, transform .12s ease;
}

.jk-combo-row:hover{
  background: var(--ut-component-highlight-background-color);
  border-color: color-mix(in sRGB, var(--ut-palette-primary), transparent 75%);
  transform: translateY(-1px);
}

.jk-title{
  font-weight:700; line-height:1.1;
  color: var(--ut-component-text-title-color);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.jk-meta{
  font-size:12px;
  color: var(--ut-component-text-muted-color);
  white-space:nowrap; overflow:hidden; text-overflow:ellipsis;
}
.jk-badge{
  margin-left:auto; padding:2px 8px; border-radius:999px;
  font-size:11.5px; font-weight:700; line-height:1;
  background: var(--ut-component-badge-background-color);
  color: var(--ut-component-badge-text-color);
  border: 1px solid var(--ut-component-border-color);
}
</style>

<div class="jk-combo-row">
  <div style="flex:1 1 auto;min-width:0;">
    <div class="jk-title">&ENAME.</div>
    {if ?JOB/}<div class="jk-meta">&JOB.</div>{endif/}
  </div>
  <span class="jk-badge">#&EMPNO.</span>
</div>

NOTA: Si os fijáis en el el código anterior, se aplica estilo CSS directamente auto-contenido en el propio HTML, pero esto se ha hecho así sólo para el propósito del ejemplo. Una buena práctica, por supuesto, sería separar el CSS y colocarlo donde corresponda, a nivel de aplicación.

Sólo nos resta guardar y ejecutar estos cambios para visualizar la nueva apariencia de nuestro ComboBox.

Conclusión

Este post me ha permitido realizar un pequeño viaje a mis recuerdos y rememorar cómo Joel era ese tipo de persona capaz de cambiar la atmósfera de una conferencia con su sola presencia: cercano, entusiasta y con una habilidad única para hablar de tecnología de forma accesible, sin perder la profundidad.

Ojalá, como comunidad, sigamos manteniendo viva esa ilusión de compartir**,** aprender y celebrar juntos cada pequeño avance.

Que estas líneas sirvan como un modesto homenaje a quien supo contagiar al mundo el espíritu colaborativo que sigue siendo el corazón de Oracle APEX y de su comunidad.

¡Gracias por llegar hasta aquí!

Happy coding,

Juan L.

More from this blog

A

APEX Unboxed

13 posts

Reflexiones y guías prácticas sobre Oracle APEX, diseño de aplicaciones, arquitectura y evolución de soluciones basadas en base de datos.