Guía de iniciación al data binding en Angular

Última actualización: 17 octubre, 2020

¿Qué es el databinding?

El databinding es la forma que tiene Angular para permitirnos mostrar contenido dinámico en lugar de estático (en inglés, hardcoded). Podríamos traducir el databinding como "comunicación" entre nuestro código HTML (archivo .html) y nuestra lógica de programación (archivo .ts).

🤷‍♀️ ¿MÁS PERDID@ QUE UN PULPO EN UN GARAJE? 🐙

Si acabas de aterrizar aquí y estos temas de Angular te suenan a chino, te recomiendo que empieces por este artículo de introducción a Angular con las claves para entenderlo.

Angular nos proporciona varias maneras de comunicación entre archivos. Podemos: 

  • mostrar información en el HTML (también conocido como template) desde el archivo .ts.
  • pasar información al archivo TypeScript (en adelante, TS) dada por el usuario al hacer click en un botón, por ejemplo. Es lo que se conoce como ''reaccionar a eventos del usuario''.
  • combinar (a la misma vez) ambas formas de intercambio de información.

databinding = comunicación

código TS (lógica de programación)

mostrar información

string interpolation {{ data }}

property binding [property]="data"

reaccionar a eventos del usuario

event binding (event)="expression"

combinación de ambos

two way databinding [(ngModel)]="data"

template (HTML)

Ejemplo para nuestra demo

Para entender las diferentes formas que existen de databinding, vamos a crearnos un ejemplo. Reutilizaremos el ejemplo de esta parte de mi artículo sobre componentes. Es decir, necesitamos un componente counter y un componente counters, y mostraremos dos veces el componente counter al incluirlo dos veces dentro del componente counters.

Sigue las indicaciones del artículo hasta la sección "Añadiendo CSS a un componente con el apoyo de Bootstrap". Una vez hecho, deberías ver este resultado en tu navegador:

componentes anidados angular

Tipos de databinding

Partiendo de este ejemplo, que simplemente muestra contenido estático, vamos explicar cada uno de los tipos de databinding.

String interpolation

Imaginemos que hay cierto contenido de nuestro CounterComponent que queremos mostrar de manera dinámica. Por ejemplo, un contador podría tener un identificador único (un ID, vaya) y un estado, como on off (es decir, el contador puede estar encendido o en pausa)

Podemos modificar nuestro counter.component.html para que refleje esto por el momento:

<p>Counter with ID (contenido dinámico aquí) is currently (contenido dinámico aquí)</p>

En una app real, probablemente ese contenido dinámico vendría de una http request o de algún tipo de cálculo, pero en esta demo simplemente vamos a escribirlo nosotros, hardcodeden el counter.component.ts. Las propiedades que crearemos serán counterId (un número) counterStatus (un string).

import { Component } from '@angular/core';

@Component({
  selector: 'app-counter',
  templateUrl: './counter.component.html'
})
export class CounterComponent {
  counterId = 10;
  counterStatus = 'off';
}

Para poder mostrar esas dos propiedades en la template del CounterComponent necesitamos usar alguna modalidad de data binding. Lo normal en un caso como este es usar string interpolation

Sintaxis

{{ string o expresión TS que resulte en una string }}

Esto incluye el caso en el que hagamos referencia a una propiedad del archivo TS de tipo string (es de hecho el caso más común), por ejemplo:

<p>Counter with ID {{ counterId }} is currently {{ counterStatus }}</p>

Pero también podríamos poner cualquier palabra de ese <p> en modo string interpolation, y no habría ningún problema, porque seguiría siendo un string, no rompiendo así la sintaxis. 

<p>{{ 'Counter' }} with ID {{ counterId }} is currently {{ counterStatus }}</p>

Aunque la verdad que eso no tendría mucho sentido. 🙃

Fíjate que el counterId es un número, no una string. Sin embargo, la regla de la sintaxis no se rompe, ya que JS hace type coercionconvirtiendo un número en una string cuando así lo considere, y eso es lo que hace en este caso.

string interpolation ejemplo

Para demostrar que la sintaxis del string interpolation admite cualquier cosa que resulte en una string, vamos a crearnos un método en nuestro archivo counter.component.ts que simplemente devuelva la propiedad counterStatus: 

  counterId = 10;
  counterStatus = 'off';

  getCounterStatus() {
    return this.counterStatus;
  }

Sustituimos el {{ counterStatus }} del counter.component.html por el método getCounterStatus() para obtener un resultado mediante string interpolation.

<p>{{ 'Counter' }} with ID {{ counterId }} is currently {{ getCounterStatus() }}</p>

Y ahora el resultado en el navegador debería ser el mismo que antes. 😎 El string interpolation es uno de los muchos temas que aprendí en este curso de Angular.

Property binding

Veamos el segundo tipo de comunicación dinámica en Angular.

Sintaxis:

[atributo HTML] = "expresión"

1. Vamos a permitir al usuario que añada nuevos contadores a nuestra app. Para eso, vamos a nuestro componente CountersComponent. Desde aquí creamos un botón para permitir al usuario crear nuevos contadores. Le añadimos un par de clases CSS para mejorar su aspecto. 

<button class="btn btn-info my-2">Add Counter</button>
<app-counter></app-counter>
<app-counter></app-counter>

Si guardamos los cambios, verás que en tu navegador tienes un botón que no hace nada al hacer click 😅. Más adelante aprenderemos a reaccionar eventos de usuario. Por ahora, vamos a centrarnos en entender el property binding. 💪

2. Vamos al archivo counters.component.ts y creamos una propiedad llamada allowNewCounter y le damos el valor de false, porque a priori no queremos permitir que el usuario cree un nuevo contador.

3. Deshabilitamos el botón en el counters.component.html de la manera tradicional, es decir, usando el atributo disabledDe esta forma está deshabilitado, pero no de manera dinámica, porque no tenemos forma de habilitarlo a menos que quitemos ese atributo.

<button class="btn btn-info my-2" disabled>Add Counter</button>
🧐¡Ojo al dato! Esta forma de comunicación se llama "property binding", pero el término "property" hace referencia a las propiedades que tiene un elemento HTML, también llamadas atributos. Como el ejemplo del atributo "disabled" de arriba. 

Así que cuando hablamos de property en el contexto del property binding nos estamos refiriendo a un atributo de una etiqueta HTML, y no a las propiedades que podemos crear en nuestro archivo de TS. En el momento en que usamos los corchetes en un atributo de HTML, éste deja de serlo, y se convierte en una propiedad dinámica de Angular. Aquí una tablita de referencias:

Como decíamos, con el atributo disabled sencillamente conseguimos que el botón está deshabilitado siempre, pero lo queremos conseguir es que esté habilitado bajo alguna circunstancia. Vamos a configurar esa circunstancia en el counters.component.ts.

  • nos ayudamos de la función setTimeout() para simular un cambio que habilite nuestro botón al cabo de X segundos.
    • para eso, le cambiamos el valor a allowNewCounter por su valor contrario (true), para que adquiera el valor de true al cabo de X segundos.

La función setTimeout() va en el constructor, que es simplemente un método ejecutado por Angular en el momento en el que el componente se crea.

import { Component, OnInit } from '@angular/core';

@Component({
  selector: 'app-counters',
  templateUrl: './counters.component.html',
  styleUrls: ['./counters.component.css']
})
export class CountersComponent implements OnInit {

  allowNewCounter = false;

  constructor() {
    setTimeout(() => {
      this.allowNewCounter = true;
    }, 2000);
   }

  ngOnInit() {
  }

}

Con esto, nuestro resultado en el navegador no ha cambiado, porque el atributo disabled sigue siendo una propiedad estática del botón. Vamos a cambiar eso y convertirla en dinámica. 💪

4. En el archivo counters.component.html, vinculamos el atributo disabled mediante property binding [ ] y le asignamos una expresión (allowNewCounter) que viene de nuestro archivo counters.component.ts. 

Pero para que esto tenga sentido, a la propiedad allowNewCounter debemos darle el valor de false, porque ese es su valor inicial cuando se inicia la app. Así que en nuestra expresión del property binding añadimos una exclamación para invertir su valor. 

Con esto le estamos diciendo a Angular: "Activa el botón solo cuando el valor de allowNewCounter sea true, cosa que pasará 2 segundos después de iniciar nuestra app. ¡Gracias majo!" 😊.  

Ahora nuestro código debería estar así:

<button class="btn btn-info my-2" [disabled]="!allowNewCounter">Add Counter</button>

En tu navegador, abre las dev tools y fíjate cómo cambia el DOM al cabo de dos segundos, eliminando el atributo disabled del botón. 😮

¿Cómo saber cuándo usar string interpolation y cuándo property binding?

Es importante que entendamos que habrá ocasiones en las que podamos usar o string interpolation o property binding obteniendo un mismo resultado.  Siguiendo con nuestro ejemplo de arriba, supongamos que queremos mostrar el valor de la propiedad allowNewCounter en el navegador. Esto podemos hacerlo de dos maneras:

Mediante string interpolation, así:

<p>{{ allowNewCounter }} </p>

Esto nos mostrará en el navegador el valor de allowNewCounter, que será false durante 2 segundos y luego pasará a ser true. 

Mediante property binding, así:

<p [innertext]="allowNewCounter"></p>

Verás que el resultado es idéntico. 

En términos generales, si quieres mostrar alguna información en el navegador, usa string interpolation. Si quieres cambiar o alternar el contenido que se muestra en el navegador, usa property binding

Event binding

Event binding es la forma de comunicación que utilizamos cuando queremos reaccionar a algún evento provocado por el usuario. Por ejemplo, queremos que algo ocurra cuando el usuario haga clic en nuestro botón de "Add Counter", una vez pasen los 2 segundos y se active.

1. Para eso, nos vamos al archivo counters.component.ts y nos creamos una propiedad llamada counterCreationStatusque tomará el valor de un string que indicará si un contador nuevo ha sido creado o no. En principio indicaremos que no ha sido creado.

  allowNewCounter = false;
  counterCreationStatus = 'No counter was created yet';

Esa información la queremos mostrar en el navegador, así que utilizaremos string interpolation en el counters.component.html.

<button class="btn btn-info my-2" [disabled]="!allowNewCounter">Add Counter</button>
<p>{{ allowNewCounter }} </p>
<p [innertext]="allowNewCounter"></p>
<p>{{ counterCreationStatus}}</p>
<app-counter></app-counter>
<app-counter></app-counter>

2. Volvemos a nuestro archivo counters.component.ts y creamos un método llamado onCreateCounter(). La razón por la que lo llamamos así es para dejar claro que será un evento que ocurrirá cuando el usuario haga algo. Con su acción, disparará el evento que llamará al método. Con esto facilitamos la comprensión del método al leerlo, porque se entiende que quiere decir: "Al crear un contador, haz X".

Dentro del método, cambiamos el valor de nuestra propiedad counterCreationStatus por una frase que represente lo contrario.

export class CountersComponent implements OnInit {

  allowNewCounter = false;
  counterCreationStatus = 'No counter was created yet';

  constructor() {
    setTimeout(() => {
      this.allowNewCounter = true;
    }, 2000);
   }

  ngOnInit() {
  }

  onCreateCounter() {
    this.counterCreationStatus = 'A counter was created!';
  }

}

De vuelva al counters.component.html, vinculamos el método onCreateCounter() con un click event al botónusando la sintaxis que nos proporciona Angular.

Sintaxis:

(evento)="método que se dispara cuando el evento ocurre"

El método puedes tenerlo en tu archivo TS o directamente en tu template, pero lo más recomendable es que toda la lógica de programación vaya en el archivo TS, así que ese es el enfoque que tomaremos.

<button class="btn btn-info my-2" [disabled]="!allowNewCounter" (click)="onCreateCounter()">
  Add Counter
</button>

Lista de referencia de eventos del DOM (podemos vincular nuestro método a cualquiera de estos eventos)

Con este cambio, si ahora haces click en el botón, el texto "No counter was created yet" debería cambiar por "A counter was created!". ¡Genial! ✨ 👏 🎉

Uso de la palabra clave $event

Hay un aspecto importante del event binding que tenemos que mencionar, y es el uso de la palabra reservada (en inglés, keyword) "$event". Vamos a verlo con un ejemplo. Imaginemos que queremos añadir un campo para que el usuario introduzca el nombre que quiere darle al contador a crear. Así que añadimos una label y un input en el counters.component.html, al principio del archivo.

1. Añadimos un evento input al <input>, vinculado a un método que aún no hemos creado, llamado onUpdateCounterName().

El comportamiento por defecto de un evento "input" es que se dispare cada vez que el usuario presione cualquier tecla.

Así que cuando eso pase, invocaremos al método onUpdateCounterName().

<label class="font-weight-bold">Counter name:</label>
<input type="text" class="form-control" (input)="onUpdateCounterName()">

Nuestro objetivo es extraer la información que el usuario introduzca en el <input>Es decir, queremos extraer el valor (en inglés, value) del <input>. Así que lo que se hace aquí es utilizar el event object para obtener cierta información del evento al que esté vinculado una etiqueta HTML. Sólo que en Angular funcionar un pelín diferente que en vanilla JS. Pero el concepto es el mismo.

En Angular, para obtener información sobre un evento en concreto, usamos la keyword "$event" como parámetro de nuestro método.

<input type="text" class="form-control" (input)="onUpdateCounterName($event)">

2. Creamos el método en el archivo TS del CountersComponent. El método espera un parámetro así que le pasamos un event. Aquí no estamos usando ninguna keyword, simplemente dándole el nombre que queramos al argumento que va a recibir nuestro método. Y como va a recibir un evento como parámetro, lo coherente es llamarlo event.

3. Hacemos un console.log de ese argumento (event) para ver qué nos devuelve la consola cuando escribimos algo en el <input>.

  onUpdateCounterName(event) {
    console.log(event);
  }

 Verás que a cada click se dispara el input event. Si despliegas cualquiera de esos eventos, llegarás a la propiedad targety dentro, a la propiedad valueAsí es como podemos acceder a lo que el usuario teclee en el <input>.

value: "hi"

input event ejemplo

Sabiendo esto, volvemos al counters.component.ts y creamos un string vacío llamado counterName. En el método onUpdateCounterName() le damos el valor de lo que sea que teclee el usuario.

  counterName = '';

  constructor() {
    setTimeout(() => {
      this.allowNewCounter = true;
    }, 2000);
   }

  ngOnInit() {
  }

  onCreateCounter() {
    this.counterCreationStatus = 'A counter was created!';
  }

  onUpdateCounterName(event) {
    this.counterName = event.target.value;
  }

Para mostrar en el navegador el resultado de lo que escriba el usuario, usamos string interpolation en el archivo counters.component.html. Podemos añadirlo debajo de nuestro <input> :

<p>{{ counterName }}</p>

¡Y listo! Ahora cada vez que escribas en el <input>, verás cómo aparece lo que escribes abajo, simultáneamente. 🎉 👏

Two way data binding

Antes de explicar este tipo de data binding asegúrate de tener importada la Directiva ngModel (que está dentro del paquete FormsModule) en el archivo app.module.ts. Este es el aspecto que debería tener tu app.module.ts:

import { BrowserModule } from '@angular/platform-browser';
import { NgModule } from '@angular/core';
import { FormsModule } from '@angular/forms';

import { AppComponent } from './app.component';
import { CounterComponent } from './counter/counter.component';
import { CountersComponent } from './counters/counters.component';

@NgModule({
  declarations: [
    AppComponent,
    CounterComponent,
    CountersComponent
  ],
  imports: [
    BrowserModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Two way data binding es una manera sencilla y corta de combinar los dos tipos de data binding que hemos visto anteriormente (string interpolation event binding, recuerda). 

En el ejemplo anterior, donde utilizábamos event binding para obtener el valor de lo que el usuario escribía en el <input> y mostrarlo en el navegador, existe la posibilidad de hacer lo mismo de manera más sencilla usando two way data binding. Veamos cómo.

Sintaxis:

[(Directiva ngModel)]="propiedad a vincular del código TS"

👉 Si te cuesta recordar esta sintaxis, puedes usar el truquito del "banana in a box" como símil de lo que representan los corchetes englobando a los paréntesis. 📦 🍌📦

1. En la template del CountersComponent vamos a comentar el input que teníamos y hacer una copia exacta de él. En este nuevo input usamos la sintaxis para el two way data binding. En nuestro caso, la propiedad que queremos vincular es counterName. 

Esta configuración:

  • disparará el evento input cada vez que el usuario presione cualquier tecla dentro del <input>
  • actualizará el valor de la propiedad counterName dinámicamente. 
  • actualizará el valor del <input> si cambiamos el counterName en alguna otra parte.
<!-- <label class="font-weight-bold">Counter name:</label>
<input type="text" class="form-control" (input)="onUpdateCounterName($event)"> -->
<label class="font-weight-bold">Counter name:</label>
<input type="text" class="form-control" [(ngmodel)]="counterName">
<p>{{ counterName}} </p>

¡Y voilà! Ya tenemos el mismo comportamiento que antes, sin necesitar el método onUpdateCounterName(). Pero déjalo ahí de momento.

2. En el counters.component.html le damos cualquier valor a la propiedad counterName al declararla, por ejemplo:

  counterName = 'test name';

Si guardas los cambios, verás que en el navegador ahora el <input> está pre-rellenado con "test name", y que si intentas cambiarlo, los cambios se reflejarán también en el párrafo de abajo. 🧙‍♀️

3. Vamos a volver a activar nuestro <input> anterior en nuestro archivo counters.component.html, el que no está usando two way data binding, sino event binding. 

<label class="font-weight-bold">Counter name:</label>
<!-- event binding -->
<input type="text" class="form-control" (input)="onUpdateCounterName($event)">
<!-- two way data binding -->
<input type="text" class="form-control" [(ngModel)]="counterName">

Eso nos deja con un escenario en nuestro navegador que muestra dos <input>el primero vacío y el segundo pre-rellenado. Recuerda que el primero está vacío porque no está usando two way data binding. 

Además, el  <p>{{ counterName }}</p>  muestra el contenido de la propiedad counterNamey como ésta está vinculada mediante string interpolation, se actualizará si cambiamos su valor en cualquiera de los <input>

🧐Pero ojo, porque como ya hemos dicho, el primer <input> no está vinculado mediante two way data binding, lo que provoca que si cambiamos el valor del counterName utilizando el segundo <input>, el valor no se actualizará en el primer <input>. ¡Haz la prueba! 😵
4. Como toque final, en lugar de mostrar el nombre del contador mediante string interpolation, vamos a mostrarlo únicamente cuando el usuario introduzca algo en el <input> y haga click en ''Add Counter''.

Para eso, vamos a comentar el primer <input> en nuestro archivo counters.component.html y el párrafo donde mostramos el counterName mediante string interpolation, porque ya no los vamos a necesitar. 

<!-- event binding -->
<!-- <input type="text" class="form-control" (input)="onUpdateCounterName($event)"> -->
<!-- two way data binding -->
<input type="text" class="form-control" [(ngModel)]="counterName">
<!-- <p>{{ counterName}} </p> -->

Podemos también comentar el método onUpdateCounterName(). En el mismo archivo (el TS del CountersComponent), añadimos al método onCreateCounter() el nombre que el usuario acabe de crear. El tema del two-ways databinding es uno de los pilares básicos de Angular, que yo aprendí en este curso.

 onCreateCounter() {
    this.counterCreationStatus = 'A counter was created! Its name is ' + this.counterName;
  }

  // onUpdateCounterName(event) {
  //   this.counterName = event.target.value;
  // }

¡Y ya lo tenemos! Ahora podemos ver el nombre que el usuario le de a un contador cuando haga click en el botón "Add Counter". ¡Genial! ✨ 👏 💃

THE END!

¡Y con esto terminamos nuestra guía introductoria al databinding en Angular! Espero que hayas aprendido algo nuevo 😊.  Si te queda alguna duda, ¡nos vemos en los comentarios!

Si quieres ayudar a hacer este blog sostenible, puedes invitarme a un café digital ツ
¡Gracias!¡Gracias!

Sobre la autora de este post

Soy Rocío, una abogada reconvertida en programadora. Soy una apasionada de aprender cosas nuevas y ferviente defensora de que la única manera de ser feliz es alcanzando un equilibrio entre lo que te encanta hacer y lo que te saque de pobre. Mi historia completa, aquí. 

Más recursos de aprendizaje

En mi experiencia, la manera más eficaz para aprender Angular es combinando varias vías de aprendizaje. Uno de mis métodos favoritos son los vídeo-cursos y mi plataforma predilecta para eso es Udemy. He hecho varios cursos pero sólo recomiendo aquellos que verdaderamente me han sido útiles. Aquí van:

angular the complete guide - curso Max S.

  Max Schwarzmüller

curso angular fernando herrera

   Fernando Herrera

Si necesitas apoyo en forma de libro, puede que éstos te sirvan de ayuda:

libro 1 angular
libro 2 angular

La programación es un mundo que evoluciona a una velocidad de vértigo. Los autores de estos libros lo saben, por eso suelen encargarse de actualizar su contenido regularmente. Asegúrate de que así sea antes de adquirirlos 😌.

Participo en el programa de afiliados de Udemy y Amazon, lo que significa que, si compras alguno de estos cursos y/o libros, yo me llevaré una pequeña comisión y a ti no costará nada extra. Vamos, lo que se dice un win-win 😊.

Otros artículos que pueden interesarte

Guía de iniciación al data binding en Angular
¿Qué es el databinding?El databinding es la forma que tiene Angular para permitirnos mostrar contenido dinámico en lugar de estático (en inglés, hardcoded). Podríamos[...]
Días del 353 al 386
Objetivos versus realidad Y nuevamente, llegó otro día clave. Llegó…y pasó. El pasado 4 de marzo este Reto Computer Geek[...]
Angular: Entendiendo la Directiva ngModel
Angular es un framework que nos permite, entre otras cosas, añadir contenido dinámico a nuestros archivos HTML. Una de las formas[...]
Si crees que este post puede serle útil a alguien, por favor, ¡compártelo!:

4 comentarios en «Guía de iniciación al data binding en Angular»

  1. Excelente la forma tan detallada que tienes de explicar, de lo mejor que hay en internet acerca de angular, gracias Rocío.

Deja un comentario

Este sitio usa Akismet para reducir el spam. Aprende cómo se procesan los datos de tus comentarios.

Como toda web legal que se precie, utilizamos cookies para asegurar que damos la mejor experiencia al usuario en nuestro sitio web. Si continúas utilizando este sitio asumiremos que estás de acuerdo. más información

Los ajustes de cookies de esta web están configurados para "permitir cookies" y así ofrecerte la mejor experiencia de navegación posible. Si sigues utilizando esta web sin cambiar tus ajustes de cookies o haces clic en "Aceptar" estarás dando tu consentimiento a esto.

Cerrar