Binding a propiedades en Angular al detalle

  • Por
Qué es el property binding, junto con una serie de detalles importantes sobre el bindeo a propiedades que como desarrollador Angular debes conocer.

Aunque ya hemos hablado del binding de propiedades, vamos a volver sobre este concepto pues hemos pasado por alto bastantes detalles en los que merece la pena detenerse con calma. Se trata de una característica disponible en el desarrollo de templates de los componentes, que hemos visto aplicada a lo largo varios ejemplos del Manual de Angular, pero esperamos poder ofrecer algunos conocimientos extra que seguramente te vendrán bien.

Comenzaremos repasando de nuevo el concepto, para ofrecer luego diversas explicaciones adicionales sobre cómo funciona el property binding. Además resolveremos algunas dudas comunes de las personas que se inician en Angular.

Qué es el bindeo a propiedades

El binding a propiedades, o "property binding" en inglés, sirve para asignar un valor a una propiedad de un elemento de un template. Esa asignación podrá ser un valor literal, escrito tal cual en el template, pero generalmente se tratará de un valor obtenido a través de una propiedad del componente, de modo que si el estado del componente cambia, también cambie la propiedad del elemento asignada en el template.

Para que no quede lugar a dudas tenemos que definir exactamente qué es una propiedad. De hecho, en el párrafo anterior hemos usado la palabra "propiedad" para referirnos a dos cosas, lo que puede dar mayor pie a confusión.

Propiedades de componentes

Los componentes generados con Angular se implementan mediante una clase, de programación orientada a objetos. Las propiedades de esa clase, los datos que almacena el componente, son lo que llamamos "propiedades del componente".

Generalmente en este artículo cuando nos referimos a "property binding" no nos referimos específicamente a propiedades del componente, sino a propiedades expresadas en un template. Éstas pueden ser propiedades de elementos HTML (propiedades del DOM de esos elementos) o propiedades de componentes en general.

Propiedades expresadas en el template

En el HTML del componente, lo que llamamos el template o la vista, las propiedades son cualquier cosa a las que asignamos valores por medio de binding. Esto lo podemos ver bien con un ejemplo.

A continuación tienes elementos del HTML a los que definimos valores por medio de atributos.

<img src="imagen.jpg">
<button disabled>Estoy desactivado</button>

A esos atributos de las etiquetas les asignamos valores, que sirven para inicializar los elementos HTML. Debes de saber de sobra cómo funcionan.

Tal como están, esa etiqueta IMG o ese botón tendrán siempre el mismo valor en sus propiedades "src" y "disabled". Sin embargo, si quisieras asignar un valor dinámico a uno de esos atributos, tomando algo definido mediante una propiedad del componente, tendrías que acudir al property binding. Se define el bindeo a propiedad mediante una sintaxis especial de Angular, asunto de este artículo.

<img [src]="rutaImagen">
<button [disabled]="estadoBoton">Estoy activado o desactivado</button>

En este caso es donde encontramos las propiedades genéricas a las que nos hacemos referencia, aquellas expresadas en el template con la notación de los corchetes de inicio y de cierre.

Gracias al binding de propiedades tenemos una imagen y un botón igualmente, pero en la imagen su src se calcula en función de la propiedad del componente llamada "rutaImagen". En el caso del botón, el estado activo o desactivado, está definido por la propiedad del componente "estadoBoton".

Lo importante que debemos entender es: cuando trabajas con propiedades del template, no estás asignando valores a atributos de HTML. De hecho, al ponerle los corchetes dejan de ser atributos del HTML para pasar a ser propiedades del template de Angular.

Variantes del property binding

Mediante los corchetes puedes asignar valores dinámicos a propiedades de un componente, propiedades de directivas, o en el caso de los elementos HTML nativos, estás asignando valores directamente al DOM.

Vamos a analizar más de cerca estos casos con varios ejemplos.

<img [src]="rutaImagen">

En este ejemplo estamos colocando un valor a una propiedad de un elemento nativo del HTML, que nos acepta un string.

Sin embargo no todas las propiedades aceptan cadenas, algunas aceptan boleanos, como era el caso del botón.

<button [disabled]="estadoBoton">Estoy activado o desactivado</button>

Este es un caso interesante, porque el elemento nativo del HTML funciona de modo diferente. Si tiene el atributo "disabled" está desactivado. Si ese atributo no aparece, entonces estará activado. Ya para definir el valor de la propiedad de Angular aparecerá siempre el atributo, pero en algunas ocasiones estará desactivado y en otras activado, dependiendo del valor de la variable boleana "estadoBoton".

También podemos encontrar binding a propiedades en una directiva, como se puede ver en el siguiente código.

<div [ngStyle]="objEstilos">DIV con estilos definidos por Angular</div>

En este caso, mediante la propiedad "objEstilos" se está definiendo dinámicamente el style de esta división. Si cambia el objeto cambiará la aplicación de los estilos al elemento.

Por último, tenemos asignación a propiedades personalizadas de nuestros propios componentes.

<mi-componente [propiedadPersonalizada]="valorAsignado"></mi-componente>

Este es un caso especial, que explicaremos con detalle cuando hablemos de las propiedades @Input de componentes. Básicamente nos permiten crear cualquier tipo de propiedad en componentes, que somos capaces de definir en el padre. En ese caso concreto, mediante la propiedad del componente padre "valorAsignado" estamos aplicando el valor del componente hijo en la propiedad "propiedadPersonalizada".

Binding de una dirección

Como se ha mencionado, la asignación de una propiedad es dinámica. Es decir, si cambia con el tiempo, también cambiará la asignación al elemento al que estamos bindeando.

Volvemos de nuevo al ejemplo:

<img [src]="rutaImagen">

Al crearse la imagen se tomará como valor de su "src" lo que haya en la propiedad del componente "rutaImagen". Si con el tiempo "rutaImagen" cambia de valor, el valor viajará también a la imagen, alterando el archivo gráfico que dicha imagen muestra.

Property binding es siempre de una dirección, de padre a hijo. El padre define un valor y lo asigna al hijo. Por tanto, aunque el hijo modificase el valor nunca viajará al padre.

Obviamente, asignando un valor a un [src] de una imagen dicha imagen no va a cambiar el valor, pero en el caso de un componente creado por nosotros sí que podría ocurrir.

<app-cliente [nombre]="nombreCliente"></app-cliente>

En este caso, el padre ha definido que el nombre del cliente sea lo que éste tiene en su propiedad "nombreCliente". Podría ocurrir que el componente app-cliente cambiase el valor de su propia propiedad "nombre". Si eso ocurre, el componente padre no notará nada por darse un binding de una única dirección (padres a hijos).

Nota: En breve explicaremos cómo es posible crear componentes que acepten valores de entrada en sus propiedades. Esto adelantamos que se hace con el decorador @Input al definir la propiedad en la clase del componente.

Valores posibles para una propiedad

Entre las comillas asignadas como valor a una propiedad podemos colocar varias cosas. Lo común es que bindeemos mediante una propiedad del componente, tal como se ha visto en ejemplos anteriores, pero podríamos colocar otro código TypeScript.

Así, dentro del valor de una propiedad, podemos usar un pequeño conjunto de operadores como el de negación "!", igual que teníamos en las expresiones en el binding por interpolación de cadenas.

Además vamos a ver un ejemplo interesante porque nos dará pie a explicar otras cosas: podríamos bindear a un literal.

<img [src]="'ruta.jpg'">

En este caso "ruta.jpg" está escrito entre comillas simples, luego es un literal de string. Quiere decir que Angular lo evaluará como una cadena, lo asignará a la propiedad y se olvidará de él. Esto no tiene mucho sentido, ya que lo podríamos haber conseguido exactamente el mismo efecto con el propio atributo HTML, sin colocar los corchetes.

<img src="'ruta.jpg'">

Esta posibilidad (la asignación de un literal) tendrá más sentido al usarlo en componentes personalizados.

<app-cliente nombre="DesarrolloWeb.com"></app-cliente>

Al no colocar la propiedad entre corchetes, es como hacer un binding a un literal de string. Por tanto, el componente app-cliente recibirá el valor "DesarrolloWeb.com" en su propiedad "nombre" al inicializarse, pero no se establecerá ningún binding durante su existencia.

También podemos bindear a un método, provocando que ese método se ejecute para aplicar un valor a la propiedad bindeada.

<p [ngClass]="obtenClases()">Esto tiene class o clases dependiendo de la ejecución de un método</p>

En este caso, cada vez que cambie cualquier cosa del estado del componente, se ejecutará de nuevo obtenClases() para recibir el nuevo valor de clases CSS que se deben aplicar al elemento.

Nota: El código de tu método obtenClases() debería ser muy conciso y rápido de ejecutar, puesto que su invocación se realizará muy repetidas veces. En definitiva, debes usarlo con cuidado para no afectar al rendimiento de la aplicación.

Evitar efectos laterales

Del mismo modo que ocurría con las expresiones en la Interpolación de strings, se debe evitar que al evaluar el valor de una propiedad se cambie el estado del componente.

Por ejemplo, si en la expresión a evaluar para definir el valor de una propiedad colocas una asignación, verás un error de Angular advirtiendo este asunto.

<img [src]="ruta = 'ruta.jpg'">

Esto último no se puede hacer. Angular se quejará con un mensaje como "emplate parse errors: Parser Error: Bindings cannot contain assignments".

Ten en cuenta que, al bindear una propiedad mediante el valor devuelto por un método, Angular no mostrará errores frente a efectos laterales producidos por modificar el estado del componente. Por ejemplo en:

<img [src]="calculaSrc()">

Si en calculaSrc() cometemos la imprudencia de modificar el estado, Angular no será capaz de detectarlo y podremos encontrar inconsistencias entre las propiedades del componente y lo que se está mostrando en el template.

De momento es todo lo que tienes que saber sobre el bindeo de propiedades. En el siguiente artículo revisaremos otra de las preguntas frecuentes de las personas que comienzan con Angular, ¿Cuándo usar interpolación o bindeo a propiedades?.