Store Undo Redo para Angular | ng-hub-ui-history
Store de undo y redo para Angular con APIs compatibles con Signals, transacciones, límites y soporte para formularios reactivos.
Última actualización 20 sept 2026
Visión General
Por qué los equipos buscan esta librería
Usa este store history para Angular cuando necesites undo y redo sobre estado complejo sin introducir una librería externa de estado completa.
Instalación
npm install ng-hub-ui-historyIr a
Ideal para
- editores
- constructores de formularios
- herramientas low-code
- interfaces de configuración
Sobre history
ng-hub-ui-history es especialmente útil en editores Angular, constructores de formularios y pantallas de configuración donde el usuario espera poder deshacer con seguridad. Lleva patrones de undo y redo a flujos con estado sin obligarte a tomar una decisión arquitectónica pesada.
Guías de uso
Commits manuales y viaje en el tiempo
Rastrea los cambios de estado y desplázate hacia atrás y hacia adelante por un historial lineal.
Ejemplos:
Historial básico
Commit manual, deshacer y rehacer sobre un único objeto rastreado.
{
"title": "Getting Started with History",
"description": "Edit and commit to create undo/redo entries."
}Objetos y arrays anidados
Usa el rastreo basado en parches para grafos de objetos profundos y mutaciones de listas.
Ejemplos:
Historial de objetos anidados
Propiedades anidadas y actualizaciones de listas registradas como parches.
{
"id": "invoice-1",
"customer": {
"name": "Acme Corp",
"city": "Madrid"
},
"lines": [
{
"name": "Support plan",
"quantity": 1,
"unitPrice": 150
}
]
}Rastreo automático de formularios
Realiza commits automáticos de los cambios de valor del formulario con los helpers de observación integrados.
Ejemplos:
Observación de formulario reactivo
watchForm() confirmando por su cuenta cada cambio de valor del FormGroup.
{
"name": "Maria",
"email": "maria@demo.local",
"role": "Editor"
}Transacciones y retención
Agrupa varias operaciones en una sola entrada y recorta las entradas antiguas según los límites configurados.
Ejemplos:
Transacciones y límites
Commits agrupados por una transacción, bajo límites de entradas y bytes.
Pointer: -1 / Entries: 0 / Bytes: 0
{
"id": "transaction-editor",
"title": "Release notes draft",
"content": "Initial draft content.",
"tags": [
"draft"
]
}Características clave
Cambios recientes
Version 22.0.6 - 9/20/26, 12:00 AM
changed: The npm keywords name the problem the package solves — undo-redo, time-travel, state-management, store, transactions, diff, patch, reactive-forms — which is what somebody looking for it would type. Metadata only: no code, types or styles change.
Version 22.0.5 - 9/16/26, 12:00 AM
changed: Repository, issue and README links follow the move to the hub-env organization. Issues for every Hub UI package are now gathered in hub-env/hub-ui, and the repository and bugs fields of the manifest point at the new addresses. No code, types or styles change.
Version 22.0.4 - 9/6/26, 12:00 AM
fixed: The published manifest no longer declares a main entry. It pointed at src/public-api.ts, the ng-packagr entry file, which never travels inside the tarball, so any resolver that ignores the exports map (older bundlers, legacy Jest resolution, plain require) followed it straight to a file that is not there. Dropping the field leaves exports, module and typings as the only entry points, the shape ng-packagr emits for every other library in the monorepo.
fixed: A commit that only moves a Date (or a Set, Map or RegExp) is recorded again. The default diff walked every object key by key, and those types keep their payload outside their own enumerable keys, so the comparison found nothing and produced an empty patch. An empty patch reads as no change: commit() returned false, the tracked state kept the old value that getState() and states() then handed back, and on a mixed commit undo() restored the other fields while leaving the new date in place, all without an error. Those values are now compared and replaced as a whole, which is what structuredClone already round-trips; an instance rebuilt with the same content still records no entry.
Version 22.0.3 - 9/1/26, 12:00 AM
changed: The homepage in the manifest points at this library's own documentation page rather than at the site root. It is the link a registry shows beside the package and the one a reader clicks from it, and landing on a front page they then have to search is a worse answer than landing on the reference for the package they were already looking at. Metadata only — no code, no types, no styles change, and nothing a consumer imports is affected.
Version 22.0.2 - 8/8/26, 12:00 AM
fixed: Documentation links now point at the canonical localized URLs. The README linked to https://hubui.dev/<path> with no locale prefix and no trailing slash, and both forms are 301-redirected, so every reader arriving from npm or GitHub landed on a redirect instead of the canonical page.
Version 22.0.1 - 7/28/26, 12:00 AM
added: Test suite for the diff/patch/clone utilities and multi-object undo/redo: cloneDeep isolation (nested structures, Dates), createDefaultDiff/applyDefaultPatch round-trips across representative shapes (nested objects, array insert/remove/reorder, key deletion, null transitions, deep nesting), estimateBytes sanity, and store-level coverage for independent per-object timelines, no-op transactions and redo invalidation after transactional commits. No runtime changes.
Version 22.0.0 - 6/17/26, 12:00 AM
changed: Aligned with Angular 22.
changed: README documentation standardized.
Version 0.1.0 - 6/17/26, 12:00 AM
added: Initial release with multi-object linear history.
added: Undo/redo, transactions, and maxEntries/maxBytes retention limits.
added: Reactive Forms auto-commit integration via watchForm().
Librerías relacionadas
Preguntas frecuentes
¿Cómo se añade deshacer y rehacer a una aplicación Angular?
createHistoryStore() te da un store. Llama a registerObject(id, initialState) una vez, a commit(id, nextState, { label }) en cada cambio, y luego a undo(id) y redo(id), con canUndo(id) y canRedo(id) gobernando los botones. states es una signal con el valor actual de todo lo que se sigue, así que una plantilla la lee directamente. En este paquete no hay componente ni directiva: esa factoría y sus tipos son toda la superficie.
¿Puede seguir un formulario reactivo?
watchForm(id, form) se suscribe a valueChanges y hace el commit de cada cambio por ti, y devuelve la función que lo detiene: no se limpia solo, así que guarda ese callback y llámalo cuando el componente desaparezca. skipInitial ignora la primera emisión. Hace commit de form.value y no de getRawValue(), así que un control deshabilitado no está en la instantánea y un undo no lo va a restaurar. beginTransaction y endTransaction agrupan una ráfaga de ediciones en un solo paso de deshacer.
¿Cuánto histórico guarda?
maxEntries vale 100 por defecto y maxBytes 512000, contados por objeto seguido, y las entradas más antiguas son las primeras en caer; history(id) devuelve los metadatos y clearHistory(id) empieza de cero. La línea temporal es lineal y por objeto: un paso cada vez, sin ramas, sin deshacer sobre varios objetos a la vez, y no se escribe nada en almacenamiento, así que una recarga empieza vacía.
¿Enlaza Ctrl+Z por mí?
No. El paquete no tiene nada de DOM —ni atajo de teclado, ni barra de herramientas, ni ARIA—, así que el Ctrl+Z lo enlazas tú con undo(id). Hay dos cosas más que sorprenden. El store es una factoría normal, no un servicio inyectable, así que compartir uno entre componentes significa proveerlo tú. Y llamar a commit o a undo con un id que nunca registraste lanza un error en lugar de devolver false, y es deliberado: si no, una errata en un id fallaría en silencio.