ExodoLibs es una biblioteca de componentes UI para Angular 18+, que ofrece una variedad de elementos personalizables y fáciles de usar para mejorar la experiencia del usuario en aplicaciones web. Compatible con Angular 18, 19 y 20.
npm install exodolibsbash
Angular 18.x
npm install exodolibs
Angular 19.x
npm install exodolibs
Angular 20.x
npm install exodolibs
`
Instrucciones
Hay que seguir las siguientes instrucciones para un correcto uso de la librería
$3
`npm install exodolibs`
$3
En el app.module.ts (por defecto) tenemos que importar el módulo de la librería "ExodolibsModule"
`
import { ExodolibsModule } from 'exodolibs';
import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { AppComponent } from './app.component';
@NgModule({
declarations: [
AppComponent
],
imports: [
BrowserModule,
ExodolibsModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule { }
`
Paginación:
limit y skip
La versión actual soporta enviar limit y skip en las peticiones remotas para controlar paginación basada en offset.
- @Input() limit: number | null — número de elementos por página. Si se especifica, se enviará como limit en las peticiones al backend.
- @Input() skip: number | null — offset inicial. Si no se proporciona, el componente calculará skip automáticamente a partir de page y limit (por ejemplo, page=3 y limit=25 → skip=50).
Comportamiento:
- Al cambiar de página, el componente envía page, y si limit está definido, también enviará limit y skip calculado.
- Al aplicar búsqueda, filtros u ordenamiento, la paginación se reinicia (se envía page=1 y skip=0) para evitar inconsistencias.
Ejemplo de uso:
`html
[mode]="'remote'"
[proxy]="{ api: { read: '/api/items' } }"
[limit]="25"
[allowFiltering]="true"
[allowSorting]="true"
>
`
En la petición al servidor deberías recibir parámetros como limit=25 y skip=0 (primera página), y skip=25 para la página 2, etc.
API del Grid
$3
- columns: ColumnContract[] — Define las columnas del grid
- dataSource: DataSourceContract — Los datos a mostrar
- mode: 'local' | 'remote' — Modo de operación (por defecto: 'remote')
- allowSorting: boolean — Habilita ordenamiento de columnas
- allowFiltering: boolean — Habilita filtros por columna
- showPagination: boolean — Muestra controles de paginación
- limit: number — Número de elementos por página (para paginación offset)
- skip: number — Offset inicial (calculado automáticamente desde page y limit)
$3
- rebuildGrid() — Reconstruye completamente el grid (headers, columnas y datos). Útil cuando:
- Las columnas cambian dinámicamente después de la inicialización
- Después del refresh del navegador cuando los datos no se visualizan correctamente
- Se necesita forzar una reconstrucción manual del grid
Ejemplo de uso programático:
`typescript
// En tu componente
@ViewChild('myGrid') grid: ExodoGridComponent;
// Reconstruir el grid manualmente
rebuildMyGrid() {
this.grid.rebuildGrid();
}
// O cuando cambias las columnas dinámicamente
updateColumns() {
this.columns = [...this.columns, { text: 'Nueva Columna', dataIndex: 'new' }];
// No es necesario llamar rebuildGrid() aquí - se detecta automáticamente via ngOnChanges
}
`
$3
En src/styles de la app principal importamos
`
@import './../node_modules/exodolibs/assets/style.scss';
`
$3
Nuevas funcionalidades
La versión actual incluye mejoras importantes al DataGrid:
- Filtros por columna (UI integrada y búsqueda por columna)
- Ordenamiento por columna (click en cabeceras, asc/desc)
- Paginación remota y local con soporte para adaptadores de datos
Estas funcionalidades están diseñadas para ser retrocompatibles con implementaciones existentes.
$3
`html
[columns]="columns"
[dataSource]="dataSource"
mode="local|remote"
[allowFiltering]="true"
[allowSorting]="true"
[showPagination]="true|false"
[proxy]="{ api: { read: 'https://api.example.com/users' } }"
[dataAdapter]="dataAdapterFn"
[labels]="paginationLabels"
[lang]="currentLang">
`
- mode: local (usa dataSource.rows) o remote (llama a proxy.api.read).
- allowFiltering y allowSorting: habilitan UI y lógica en la grilla.
- dataAdapter: (opcional) función que transforma la respuesta cruda de la API al formato interno esperado por la grilla (ver más abajo).
- labels: (opcional) objeto con textos para el paginador — si no se provee, se usan defaults o Transloco si está disponible.
$3
Para desacoplar la grilla de la estructura específica de tu backend (por ejemplo Laravel), la propiedad dataAdapter permite pasar una función que reciba la respuesta cruda y los parámetros de petición, y devuelva un objeto con la forma JsonResponse que la grilla espera:
`typescript
// Firma: (response: any, params: any) => JsonResponse
dataAdapter(response: any, params: any) {
// mapear response a dataRecords
return {
success: true,
message: 'OK',
dataRecords: {
current_page: 1,
from: 1,
last_page: 1,
to: response.length,
total: response.length,
per_page: 10,
data: response.slice(0, 10)
}
};
}
`
Ejemplos:
- Si tu API ya devuelve un objeto de paginación tipo Laravel, tu dataAdapter puede simplemente mapear nombres distintos de campos.
- Si tu API devuelve un array (p. ej. jsonplaceholder), el dataAdapter puede simular la paginación en cliente (slice por página).
La grilla usa el dataAdapter si está presente; si no, asumirá que la respuesta ya tiene la forma JsonResponse (esto mantiene compatibilidad con código en producción que no usa adapter).
$3
El paginador intenta resolver textos en el siguiente orden de prioridad:
1. @Input() labels (valor pasado directamente al componente)
2. Proveedor global EXODO_I18N (InjectionToken)
3. Labels por defecto incluidos en la librería (español)
La librería ofrece un InjectionToken llamado EXODO_I18N que puedes proveer en tu aplicación para personalizar los textos del paginador sin necesidad de un sistema de i18n externo.
Si quieres integrar un sistema de traducciones (p. ej. Transloco) puedes hacerlo en tu aplicación y proveer EXODO_I18N desde tus recursos de traducción. La integración directa con librerías externas no es obligatoria y exodolibs funciona correctamente con los valores por defecto.
$3
`typescript
columns = [
{ text: 'ID', dataIndex: 'id' },
{ text: 'Name', dataIndex: 'name' }
];
paginationLabels = {
first: 'First', previous: 'Prev', page: 'Page', of: 'of', next: 'Next', last: 'Last', refresh: 'Refresh', infoTemplate: '{{from}} - {{to}} of {{total}}'
};
// Adapter para jsonplaceholder (array simple -> paginado en cliente)
dataAdapter(response: any[], params: any) {
const page = params.page || 1;
const perPage = params.per_page || 10;
const total = response.length;
const last = Math.ceil(total / perPage);
const pageData = response.slice((page - 1) perPage, page perPage);
return {
success: true,
message: 'OK',
dataRecords: {
current_page: page,
from: (page - 1) * perPage + 1,
last_page: last,
to: (page - 1) * perPage + pageData.length,
total,
per_page: perPage,
data: pageData
}
};
}
`
$3
`typescript
// Ejemplo de columnas con agrupación (encabezados multinivel) y sortable
columns = [
{
text: 'Personas',
children: [
{ text: 'Nombre', dataIndex: 'firstName', sortable: true },
{ text: 'Apellido', dataIndex: 'lastName', sortable: true }
]
},
{
text: 'Contacto',
children: [
{ text: 'Email', dataIndex: 'email', sortable: false },
{ text: 'Teléfono', dataIndex: 'phone' }
]
},
{ text: 'Registrado', dataIndex: 'createdAt', sortable: true }
];
// En el template
//
`
En este ejemplo, Personas y Contacto son encabezados que agrupan columnas hoja. Las columnas hoja con sortable: true mostrarán el icono de orden y podrán activar orden asc/desc cuando allowSorting esté activado en el grid.
$3
Para ejecutar los tests del workspace (ejecuta esto en la raíz del repo):
`bash
npm install
npm run test
`
Si hay fallos en los tests, la salida del runner (Karma/Jasmine) mostrará los detalles. Corrige fallos en los componentes afectados y vuelve a ejecutar.
$3
Antes de publicar la librería (npm publish), asegúrate de:
1. Ejecutar y dejar todos los tests verdes (npm run test).
2. Construir el paquete (ng build exodolibs o npm run build si el script está disponible).
3. Actualizar la versión en projects/exodolibs/package.json.
4. Subir tag y push al repositorio (git tag vX.Y.Z && git push --tags).
5. Ejecutar npm publish --access public desde el paquete generado si corresponde.
---
Temas y traducción del paginador
La librería ahora soporta temas y traducciones para el componente exodo-pagination.
1) Usar temas globales (SCSS): en src/styles.scss de tu aplicación puedes importar uno de los temas provistos antes de los estilos de Exodolibs:
`scss
/ Blanco Glacial es ahora el theme por defecto. Si quieres usar otro theme explícitamente puedes importarlo antes: /
@import 'node_modules/exodolibs/assets/exodostyles/themes/_light.scss'; // opcional
@import 'node_modules/exodolibs/assets/style.scss';
`
2) Aplicar tema por componente: el componente exodo-pagination acepta el @Input() theme con valores '' | 'light' | 'dark'.
`html
`
3) Traducción del paginador: puedes inyectar labels vía @Input() labels con las claves disponibles: first, previous, page, of, next, last, refresh, infoTemplate.
Ejemplo:
`html
[labels]="{
first: 'First',
previous: 'Prev',
page: 'Page',
of: 'of',
next: 'Next',
last: 'Last',
refresh: 'Refresh',
infoTemplate: '{{from}} - {{to}} of {{total}}'
}"
...>
`
Nota: si no se proveen labels, se usan textos por defecto en español.
4) Proveedor global de traducciones (opcional): puedes configurar traducciones globales para todos los componentes usando el InjectionToken EXODO_I18N.
`typescript
import { EXODO_I18N } from 'exodolibs';
@NgModule({
providers: [
{ provide: EXODO_I18N, useValue: { page: 'Page', of: 'of', infoTemplate: '{{from}}-{{to}} of {{total}}' } }
]
})
export class AppModule {}
`
Si provees labels en un componente, ese valor anulará la configuración global.
5) Uso con Transloco (opcional - recomendado para proyectos que ya usan Transloco)
Si tu aplicación usa @ngneat/transloco, ExodoPaginationComponent intentará traducir las claves bajo el namespace exodo.pagination antes de usar los textos por defecto. Las keys disponibles son:
- exodo.pagination.first
- exodo.pagination.previous
- exodo.pagination.page
- exodo.pagination.of
- exodo.pagination.next
- exodo.pagination.last
- exodo.pagination.refresh
- exodo.pagination.infoTemplate
Ejemplo (archivo de traducciones JSON):
`json
{
"exodo": {
"pagination": {
"first": "Primera",
"previous": "Anterior",
"page": "Página",
"of": "de",
"next": "Siguiente",
"last": "Última",
"refresh": "Actualizar",
"infoTemplate": "{{from}} - {{to}} de {{total}}"
}
}
}
`
Recuerda instalar @ngneat/transloco en tu proyecto y configurarlo según su documentación si quieres aprovechar traducciones automáticas.
---
Nota sobre Transloco y esta workspace:
La integración con @ngneat/transloco es totalmente opcional. exodolibs ya funciona con sus textos por defecto y mediante el InjectionToken EXODO_I18N puedes proporcionar traducciones desde tu aplicación sin depender de un paquete externo.
Si tu aplicación ya usa Transloco y quieres aprovechar traducciones automáticas para el paginador, puedes integrarlo en la aplicación y exponer las traducciones a exodolibs (por ejemplo, mediante un provider que lea las claves del namespace exodo.pagination). No es obligatorio instalar @ngneat/transloco` para usar la librería.