*ngFor para objetos: cómo obtener claves y valores sin perder rendimiento

Entrenador de Python en Línea para Principiantes

Aprende Python fácilmente sin sobrecargarte de teoría. Resuelve tareas prácticas con verificación automática, recibe pistas y escribe código directamente en el navegador, sin instalar nada.

Start Course

El problema que todo desarrollador Angular conoce

\n\n

¿Alguna vez has intentado mostrar en una plantilla de Angular el contenido de un objeto JavaScript normal usando *ngFor y de repente te diste cuenta: "¿Y cómo obtengo la clave y el valor?" Porque *ngFor por defecto solo funciona con arrays. Y un objeto no es un array.

\n\n

Esta pregunta es una de las más populares en Stack Overflow (miles de visitas y decenas de respuestas). Los desarrolladores no buscan solo una solución, sino la solución correcta, aquella que no mate el rendimiento de la aplicación, especialmente cuando el objeto es grande o se actualiza con frecuencia.

\n\n

En este artículo no solo daremos una respuesta. Analizaremos todos los enfoques principales, desde los simples hasta los avanzados, y mostraremos cómo escribir código que funcione de forma rápida y estable. ¡Allá vamos!

\n\n

¿Por qué *ngFor no funciona con objetos "de fábrica"?

\n\n

La directiva *ngFor en Angular está diseñada para estructuras iterables (Iterable). Un array es una estructura iterable. Un objeto no lo es. Cuando escribes:

\n\n
<div *ngFor="let item of myObject">{{ item }}</div>
\n\n

Angular mostrará un error: "Cannot find a differ supporting object '...'". Angular simplemente no sabe cómo iterar un objeto.

\n\n

Pero en la práctica, a menudo necesitamos mostrar datos de un objeto: configuraciones, diccionarios, respuestas de API, donde las claves tienen significado (por ejemplo, { name: 'Ana', age: 25, city: 'Madrid' }).

\n\n

La forma más simple: Object.keys() y Object.entries()

\n\n

La respuesta más popular y obvia en Stack Overflow es convertir el objeto en un array directamente en la plantilla o en el componente.

\n\n

Opción 1: Object.keys() — obtenemos solo las claves

\n\n
// En el componente (TypeScript)\nexport class MyComponent {\n  myObject = { name: 'Ana', age: 25, city: 'Madrid' };\n}
\n\n
<!-- En la plantilla -->\n<div *ngFor="let key of objectKeys(myObject)">\n  Clave: {{ key }}, Valor: {{ myObject[key] }}\n</div>
\n\n

Pero aquí hay un detalle: objectKeys debe estar disponible en la plantilla. O la hacemos un método del componente, o la colocamos en una propiedad separada:

\n\n
// Componente\nexport class MyComponent {\n  myObject = { name: 'Ana', age: 25, city: 'Madrid' };\n  objectKeys = Object.keys; // simplemente una referencia a la función nativa\n}
\n\n

Esto funciona, pero llama a la función en cada verificación de cambios (change detection). Si el objeto es grande, esto afecta el rendimiento.

\n\n

Opción 2: Object.entries() — claves y valores de una vez

\n\n
// Componente\nexport class MyComponent {\n  myObject = { name: 'Ana', age: 25, city: 'Madrid' };\n  get entries() {\n    return Object.entries(this.myObject);\n  }\n}
\n\n
<!-- Plantilla -->\n<div *ngFor="let entry of entries">\n  Clave: {{ entry[0] }}, Valor: {{ entry[1] }}\n</div>
\n\n

O con desestructuración (más legible):

\n\n
<div *ngFor="let [key, value] of entries">\n  Clave: {{ key }}, Valor: {{ value }}\n</div>
\n\n

Ventajas: simple, claro, visual.
\nDesventajas: el método entries se llamará en cada ciclo de detección de cambios. Para objetos estáticos está bien, para objetos dinámicos puede ser un problema.

\n\n

Rendimiento: ¿por qué es importante?

\n\n

Imagina que tu objeto contiene 10 000 registros. O que se actualiza cada 100 ms (por ejemplo, datos del servidor en tiempo real). Cada llamada a Object.entries() crea un nuevo array. Angular, en cada ciclo de detección de cambios, verá un array "nuevo" y redibujará toda la lista. Esto provoca parpadeos en la interfaz, pérdida de foco en los inputs y ralentizaciones.

\n\n

Por eso, para proyectos serios es necesario usar una optimización.

Blogs

Book Recommendations