Cuándo usar grid
Grid es la elección correcta cuando la audiencia necesita leer records individuales, exportar data, o verificar el detalle detrás de un summary. Los identifiers de tipo grid y table mapean al mismo renderer; cualquiera de los dos se acepta.
Usá una viz tipo chart (bar, line) cuando la pregunta es sobre una comparación o un trend en vez de las filas raw. Usá report_matrix cuando los records necesitan agrupamiento con subtotales o están diseñados para PDF export.
Mapping
El mapping para grid es mínimo — las columnas vienen del resultado de la query.
mapping.columns— opcional. Array de nombres de columna. El subset a mostrar, en el orden dado. Usalo para dropear columnas ruidosas o forzar un orden de columna específico sin cambiar la query. Cuando se omite, cada columna en el resultado de la query se renderiza, en orden de query.
mapping:
columns:
- order_date
- category
- brand
- country
- status
- revenue
Bloque grid
Las opciones de grid viven bajo el bloque top-level grid (el alias table también se acepta). Grid no tiene un bloque chart.
Display de columna
grid.column_widths— objeto mapeando nombre de columna a un ancho fijo ("120px"), proporcional ("25%"), o valor numérico (pixels).grid.frozen_columns— número de columnas leftmost a congelar, o un array de nombres de columna. Útil cuando el grid scrollea horizontal y la audiencia necesita el identifier de fila siempre visible.grid.nowrap_columns— array de nombres de columna que nunca tienen que hacer wrap; el overflow muestra elipsis.grid.labels— objeto mapeando nombre de columna a display label (overridea el nombre raw de columna en el header).
Celdas compuestas
grid.composite_columns renderiza una celda como múltiples líneas tomadas de otros fields:
grid:
composite_columns:
customer:
lines:
- field: name
class: font-semibold
- field: city
prefix: "📍 "
show_empty: false
Celdas de comparación
grid.comparison_columns— array de nombres de columna a renderizar como indicador de trend up / down / dash al lado del valor. Útil para columnas de delta donde la audiencia necesita la dirección a primera vista.
Formats
grid.column_formats— objeto mapeando nombre de columna a una format key.grid.formats— objeto mapeando format key a un pattern. La indirección de dos pasos te deja reusar el mismo pattern en muchas columnas.
Cross-filter
grid.cross_filter— boolean, defaulttrue. Seteá afalsepara suprimir click-to-filter en este grid.
Paginación
Las opciones de paginación viven bajo el bloque top-level pagination:
pagination.page_size— entero. Filas por página. Default25. Elegí más grande cuando la audiencia hace data-export; más chico cuando el escaneo es el uso típico.pagination.column_page_size— entero. Cuando las columnas visibles exceden esto, se activa un column-pager horizontal. Default8. Aliases:columns_per_page,columns_page_size.
La paginación es server-side: cambiar de página re-corre la query subyacente con los nuevos parámetros de página. Las características de costo difieren por adapter — mirá Diferencias entre adapters de source.
format
El par grid.column_formats + grid.formats es la forma primaria de formatear columnas. El field format root actúa como fallback para cualquier columna no cubierta. Usá el patrón de indirección cuando el mismo estilo de número aplica a muchas columnas:
grid:
column_formats:
revenue: currency
avg_order_value: currency
refunds: currency
item_count: integer
formats:
currency: "$#,##0.00"
integer: "#,##0"
Comportamiento de cross-filter
- Clickear una celda (cuando la columna está configurada como clickeable) cross-filtra el resto del dashboard por el nombre de columna y el valor clickeado.
- El field clickeado tiene que estar declarado como parámetro en al menos un model usado por el dashboard, o el click se ignora silenciosamente.
- El bloque top-level
emphasispuede declarativamente resaltar una fila matcheando un valor de cross-filter relacionado. - Deshabilitá por viz con
chart.cross_filter: false.
Mirá Cross-filtering para el mecanismo completo.
Ejemplos trabajados
Detalle de orden con primera columna congelada, formats de currency y una columna de comparación:
id: ec_orders_detail_grid
title: Order Detail
query: "models/ec_fulfillment.malloy::detail"
type: grid
mapping:
columns:
- order_date
- category
- brand
- country
- status
- item_count
- revenue
- avg_order_value
grid:
frozen_columns: 1
column_widths:
order_date: "120px"
revenue: "140px"
column_formats:
revenue: currency
avg_order_value: currency
item_count: integer
formats:
currency: "$#,##0.00"
integer: "#,##0"
comparison_columns:
- revenue
pagination:
page_size: 50
published: true
Roster de customers con celdas compuestas:
id: customers_grid
title: Customers
query: "models/customers.malloy::roster"
type: grid
grid:
composite_columns:
customer:
lines:
- field: name
class: font-semibold
- field: email
prefix: "✉ "
- field: city
prefix: "📍 "
show_empty: false
column_widths:
customer: "260px"
lifetime_value: "140px"
column_formats:
lifetime_value: currency
formats:
currency: "$#,##0.00"
pagination:
page_size: 25
published: true
Errores comunes
- El grid ocupa demasiado espacio horizontal. Dropeá columnas de
mapping.columnso seteá anchos más estrechos explícitos engrid.column_widths. - Los anchos de columna no quedan. Asegurate que los nombres de columna en
grid.column_widthsmatcheen los nombres de field en el resultado de query exacto. - El sorteo es solo por-página. La paginación server-side significa que los sorts client-side solo ven una página. Para ordenar entre todas las filas, ordená en la query Malloy.
- El label del header está mal. Seteá
grid.labelspara overridear el nombre raw de columna (o renombrá en la query Malloy). - El indicador de comparación apunta en la dirección equivocada. El renderer deriva dirección del signo del valor. Codificá deltas "buenos" con signo positivo y "malos" con negativo.
- Los clicks de cross-filter no tienen efecto. La columna clickeada tiene que estar declarada como parámetro en al menos un model usado por el dashboard.
- Grid esperado para agrupar filas con subtotales. Grid es plano; usá report_matrix para agrupamiento.