Aller au contenu
WebFrontAngularNews

Angular : Transformez vos inputs à volonté et simplement

Transformer simplement ces Inputs devient nettement plus facile en Angular avec la propriété transform

Introduction

Depuis les débuts d'Angular, la communication parent-enfant se fait à l'aide des annotations @Input() @Output().
@Input() est une annotation puissante qui permet de passer des données d'un composant parent à un composant enfant.
L'un des souhaits de la communauté était de pouvoir transformer facilement les données passées en entrée.

...Et bientôt, ce souhait deviendra réalité. Le but de cet article est de décrire une fonctionnalité précise d'Angular qui a fait son arrivée avec la version 16.1.

Contexte

Imaginons que nous voulions transformer un input qui prend une chaîne de caractères en paramètre en un booléen.
Cette transformation nous permettrait d'écrire

<app-expand expanded />
<app-expand expanded="true" />
<app-expand [expanded]="true" />

Pour pouvoir écrire nos appels aux composants de nos enfants de cette manière, plusieurs moyens sont à notre disposition :

  • la méthode getter et setter
  • créer sa propre annotation
  • la propriété transform du metatada de l'annotation @Input().

Getter et setter

@Component({ selector : 'app-expand' })
export class ExpandComponent {
  #expand = false ;
  @Input() set expanded(value : string | boolean) {
   this.#expand = value !== null && 
    `${valeur}` !== 'false' ;
  }
  get expanded() {
   return this.#expand ;
  }
}

La méthode getter/setter est un modèle courant dans nos composants Angular.

Dans le morceau de code précédent, lorsque le développeur définit l'input "expanded", le code setter est exécuté et la transformation est effectuée.
Dans cette transformation, je ne vérifie pas si la valeur passée est indéfinie pour permettre l'écriture HTML suivante.

<app-expand expanded />

Cette solution pourrait être suffisante, mais elle pose un très gros problème.
En général, un composant a plusieurs inputs, si chaque input nécessite une transformation, le composant peut grandir pour une valeur ajoutée très faible.

Une solution plus agréable et plus durable à l'avenir serait de créer son propre décorateur.

Créer son propre décorateur de propriété

En javascript, un décorateur est une simple fonction. Dans le cas d'un décorateur de propriété, il doit être placé avant la propriété et est décrit par une fonction prenant deux paramètres :

  • cible
  • clé

La clé représente en fait le nom de la propriété
La cible représente la fonction constructeur de la classe pour un membre statique, ou le prototype de la classe pour un membre d'instance.

Un décorateur transformant une chaîne de caractères en un booléen pourrait être le suivant.

type SafeAny = any;

function toBoolean(value: string | boolean): boolean {
  return value !== null && `${value}` !== 'false';
};

function InputBoolean(): (target: SafeAny,name: string) => void {
  return function(target: SafeAny, name: string) {
    let value = target[name];
      Reflect.defineProperty(target, name, {
      set(next: string) {
        value = toBoolean(next);
      },
      get() {
        return value;
      },
      enumerable: true,
      configurable: true,
    })
  }
}

Ce décorateur nous permet de centraliser la logique de transformation et peut être utilisé comme suit dans le composant :

@Component({ selector : 'app-expand' })
export class ExpandComponent {
  @Input() @InputBoolean() expanded = false ;
}

Pourquoi ne pas utiliser @InputBoolean seul sans @Input ? Le compilateur AOT a besoin que @Input soit visible.

Cette méthode de création d'un décorateur est élégante et permet de centraliser la logique sans avoir à ajouter des éléments superflus dans les composants.

Néanmoins, les décorateurs sont encore une notion "expérimentale" et le concept n'est pas forcément facile à comprendre au premier abord.

C'est pourquoi Angular nous permet maintenant d'utiliser la propriété simple transform dans les métadonnées du décorateur Input pour effectuer des transformations simples.

Une nouvelle façon de transformer

Depuis Angular 16, le décorateur @Input prend des métadonnées en paramètre. Cette récente nouveauté a été intégrée dans Angular pour rendre un input obligatoire.

Ces métadonnées prennent également  une fonction de transformation depuis la version 16.1.


function toBoolean(value : string | boolean) : boolean {
  return value !== null && `${value}` !== 'false' ;
} ;

@Component({ selector : 'app-expand' })
export class ExpandComponent {
  @Input({ transform : toBoolean }) expanded = false ;
}

C'est très simple, non ? La transformation se fait avec une simple fonction, ce qui augmente considérablement l'expérience du développeur.

De toute évidence, l'équipe d'Angular ne s'arrête pas là. Transformer une chaîne de caractères en un booléen ou une chaîne de caractères en un nombre est assez courant. Dans ce sens, Angular nous fournit des fonctions d'aide pour éviter de recoder cette logique.

import { booleanAttribute, numberAttribute } from '@angular/core';

Dernier