Qué es el binding a atributo, por qué debemos conocerlo. En qué casos aplica el binding de atributo y ejemplos de uso.
En este artículo vamos a conocer una cosa nueva en el Manual de Angular. Está relacionada con el binding, que hemos tratado en numerosas ocasiones, aunque se trata de un nuevo caso de binding del que no habíamos hablado anteriormente: el binding a atributo.
En si, usar el binding a atributo es muy sencillo, pues resulta en una sintaxis muy elemental que tenemos que usar. Lo complicado puede ser ver el concepto y saber los momentos en los que se debe usar. Desde luego son pocos, pero si no conocemos este concepto nos encontraremos a veces con errores de Angular que nos puede costar solucionar.
Comenzaremos por explicar qué se conoce como atributo, frente a una propiedad, y luego explicaremos la sintaxis que usaremos cuando necesitemos bindear a un atributo.
Qué es un atributo en Angular
Primero cabe decir que en este caso vamos a definir "atributo" en el contexto de Angular, ya que en el contexto de HTML entendemos atributo como los modificadores que acompañan a etiquetas.
<p class="miclase">En este párrafo usamos el atributo "class"</p>
El HTML tiene cientos de atributos y debes saber perfectamente cómo funcionan, pero no nos referimos a ellos, sino a atributos en el contexto del desarrollo en Angular.
Incluso en Angular, a menudo usamos la palabra "atributo" como sinónimo de "propiedad". En muchos casos podría valer meter todo en el mismo saco, pero lo cierto es que no siempre es lo mismo y Angular no trata a ambos de la misma manera.
Básicamente, propiedad se refiere a una característica de un objeto del DOM, definida por una propiedad del objeto de ese elemento del DOM. En muchas ocasiones, cuando escribes HTML existe una correspondencia directa entre lo que sería un atributo de HTML y lo que sería una propiedad del DOM.
Por ejemplo el atributo "id" del HTML corresponde directamente con la propiedad "id" del objeto del DOM. Pero existen atributos que no tienen un mapeo directo en el DOM, como es el caso de "colspan". Existen atributos de HTML que mapean a propiedades del DOM que no se llaman ni funcionan igual, como "class" y "classList". En general esta es la clave de la cuestión.
Pues bien, cuando hacemos bindeo a propiedades con Angular (property binding), tenemos disponibles las propiedades del elemento, pero no los atributos. Por tanto, podemos hacer esto:
<div [id]="idDivision">Test de binding a propiedad</div>
Pero no podemos hacer esto otro:
<td [colspan]="1 + 1">test</td>
En el momento en el que intentamos hacer un binding a propiedad, sobre una propiedad que no existe en el DOM del elemento y que Angular no entiende, obtendremos un mensaje como este: Can't bind to [...] since it isn't a known property of [...].
Ni tan siquiera podemos acudir a la interpolación de strings para resolver este problema. Si intentamos algo como esto tampoco funcionará:
<td colspan="{{1 + 1}}">test</td>
El asunto es que, tanto string interpolation como property binding son capaces de bindear únicamente a propiedades definidas en Angular y no a atributos del HTML.
Sintaxis para bindear a un atributo
La sintaxis necesaria para que Angular procese el binding a un atributo, sin producir ningún mensaje de error, es muy parecida a la sintaxis de binding a una propiedad que ya conocemos. Solo tenemos que especificar que en ese preciso momento estamos bindeando a un atributo. Si antes colocábamos la propiedad entre corchetes, ahora colocaremos "attr." seguido del nombre del atributo.
<td [attr.colspan]="1 + 1">test</td>
Por ver otro ejemplo, los "data attribute" tampoco tienen mapeo a propiedades. En estos casos, si queremos bindear a un "data attribute" del HTML5, tendremos que hacerlo con la sintaxis que acabamos de conocer.
Por si no sabes qué es un "data attribute", tiene un aspecto como este:
<div data-cliente="DesarrolloWeb.com">Desarrollo Web</div>
Ahora, si en el TypeScript de nuestro componente tenemos un objeto cliente definido, como podría ser:
cliente = {
nombre: 'DesarrolloWeb.com'
}
Y queremos bindear ese nombre en el data attribute, haríamos algo como esto
<div [attr.data-cliente]="cliente.nombre">{{cliente.nombre}}</div>
Ejemplo completo de componente que implementa bindeo a atributo
Vamos a ver ahora un ejemplo de un componente que realiza el binding a atributo, de modo que podamos practicar algo. Es un componente que nos muestra los puntos donde se situa un polígono. Queremos mostrar los datos del polígono haciendo uso de una tabla en la que hay una casilla que está expandida en varias columnas.
La tabla resultante que queremos conseguir tendrá este aspecto:
PONER IMAGEN
Comenzaremos viendo la definición TypeScript de nuestro componente, en la que podremos observar la especificación de los datos de nuestro polígono en una propiedad "poligono" del componente.
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'dw-datos-poligono',
templateUrl: './datos-poligono.component.html',
styleUrls: ['./datos-poligono.component.css']
})
export class DatosPoligonoComponent implements OnInit {
poligono = {
nombre: 'cuadrado',
puntos: [
{
x: 10,
y: 5
},
{
x: 15,
y: 5
},
{
x: 15,
y: 10
},
{
x: 10,
y: 10
}
]
}
constructor() { }
ngOnInit() {
}
}
Ahora veamos la parte más representativa de este componente, en el objetivo del artículo, de aprender el bindeo a atributos.
<table>
<tr>
<th>Nombre</th>
<th>Lados</th>
<th [attr.colspan]="poligono.puntos.length">Puntos</th>
</tr>
<tr>
<td>{{poligono.nombre}}</td>
<td>{{poligono.puntos.length}}</td>
<td *ngFor="let punto of poligono.puntos">{{punto.x}},{{punto.y}}</td>
</tr>
</table>
El bindeo de atributo nos permite hacer que la celda de la tabla donde pone "puntos" se expanda en un número de celdas igual al número de puntos del polígono. Dependiendo de la definición de ese polígono las celdas de la tabla se adaptarán a las necesidades de cada caso.
Luego nos quedaría simplemente colocar unos estilos, a placer. Que, para que se parezcan a la tabla que hemos mostrado en la imagen de antes, podrían ser como estos:
table {
border: 1px solid darkgoldenrod;
margin: 20px;
}
th {
background-color: rgb(220, 224, 152);
text-align: center;
padding: 10px;
}
td {
padding: 5px;
border: 1px solid #ddd;
}
Eso es todo. Como has visto, el bindeo a atributos es muy sencillo. Sólo hay que tener claro el concepto y cuándo se debe aplicar. Ahora si te encuentras en una situación similar, simplemente acuérdate de este artículo, o busca en Google ;).
Miguel Angel Alvarez
Fundador de DesarrolloWeb.com y la plataforma de formación online EscuelaIT. Com...