Signal Input : comment ça marche ?

Dans notre précédent article Angular Signals : que faut-il retenir quand je débute ?, nous avons exploré ce qui se cache derrière les Signals en Angular. Aujourd'hui, nous aborderons l'un des concepts liés aux Angular Signals : les Signal Inputs, comme l'indique le titre de l'article. L'objectif est de comprendre ce que c'est, comment l'utiliser et pourquoi l'utiliser.

Qu'est-ce qu'un Signal Input en Angular ?

Avant de définir ce qu'est un Signal Input, faisons un peu d'histoire. En Angular, pour passer des propriétés d'un composant parent A à un composant enfant B, nous utilisons habituellement les @Input(). Voici un exemple :

import {Component, input} from '@angular/core';
@Component({...})
export class ComponentB {
  @Input() age: number;
}

<!--- Parent component side (ComponentA) --->
<component-b [age]='10' />

Avec l'arrivée de Signal en Angular, la core team de Angular a introduit une nouvelle méthode pour gérer cette communication, appelée Signal Input, afin d'optimiser les performances du framework.

Le Signal Input joue le même rôle que @Input()c'est-à-dire permettre l'injection de données du composant parent A vers le composant enfant B.

Comment utiliser un Signal Input ?

Angular prend en charge deux variantes de Signal Input à savoir :

  • Optional input : Il faut souligner que le Signal Input est optionnel par défaut. Tout comme le @Input(), si au niveau du composant parent A, nous ne faisons pas passer l'input en propriété au composant enfant B, ce n'est pas bloquant. Voici un exemple de composant utilisant le Optional Signal Input :

      import {Component, input} from '@angular/core';
      @Component({...})
      export class MyComp {
        // optional
        firstName = input<string>();         // InputSignal<string|undefined>
        age = input(0);                      // InputSignal<number>
      }
    

    Pour le Signal Input nommé firstName, on note que le type est string | undefined. En effet, si l'on ne spécifie pas une valeur initiale à un Signal Input qui optionnel même après l'avoir typé, Angular utilisera le type undefined de façon implicite. Il faut donc penser à initialiser votreSignal Inputavec une valeur quand il est optionnel.

  • Required input : Ici, le Signal Input est rendu obligatoire et il est nécessaire d'indiquer le type de la donnée à recevoir. En voici un exemple :

      import {Component, input} from '@angular/core';
      @Component({...})
      export class MyComp {
        // required
        lastName = input.required<string>(); // InputSignal<string>
      }
    

Tout comme le @Input() classique que nous connaissons jusque-là, le Signal Input aussi peut être utilisé avec des alias. Le but des alias c'est d'éviter des conflits de noms d'attributs. Voici un exemple lié à l'utilisation d'un alias sur un Signal Input :

import {Component, input} from '@angular/core';
@Component({...})
export class MyComp {
  age = input(0, {alias: 'studentAge'});
}

<!--- Parent component side --->
<my-comp [studentAge]='10' />

A présent, nous parlerons d'une spécifité propre au Signal Input que nous n'avons pas avec @Input(). Il s'agit de la transformation de valeur [cette expression fait penser aux Pipes 😃]. En effet, tout comme la philosophie derrière un Pipe, nous sommes capables avec un Signal Inputde faire un traitement sur la valeur d'entrée sans en modifier le sens. La transformation convertira donc la valeur brute envoyée par le parent au type d'entrée attendu. La transformation doit être une fonction pure. En voici une illustration :

class MyComp {
  disabled = input(false, {
    transform: (value: boolean|string) => typeof value === 'string' ? value === '' : value,
  });
}

Dans l'exemple ci-dessus, nous déclarons un Signal Input nommé disabled qui accepte des valeurs de type boolean et string. Ces valeurs (peu importe quelles soientbooleanoustring) sont ensuite traitées enbooleanavec la transformation, ce qui donne desboolean.

De cette façon, nous ne traitons que du boolean à l'intérieur de notre composant enfant lorsque nous appelons this.disabled(), tandis au niveau de notre composant parent, nous pouvons passer un string comme raccourci pour marquer notre composant disabled.

Pour finir, tout ce qui a été abordé dans ce précédent article concernant les Signals est valable pour les Signal Inputs à savoir les méthodes computed() et effect().

Pourquoi et quand faut t-il choisir Signal Input au lieu de @Input() ?

Le Signal Input est une alternative réactive à la méthode @Input(). Voici les nombreux avantages qu'offrent un Signal Input en nous basant sur la documentation :

  • Le required input de Signal Input ne nécessite pas de valeur initiale ou d'astuce pour indiquer à TypeScript qu'un input a toujours une valeur.

  • Les transformations (transform) sont automatiquement vérifiées pour correspondre aux valeurs acceptées.

  • Les Signal Inputs, lorsqu'ils sont utilisées dans des templates, marqueront automatiquement les composants OnPush en dirty. Avec@Input(), il fallait le faire soi-même pour permettre le changement de détection.

  • L'utilisation de la méthode effect() au lieu de ngOnChanges() ou setters qui rend plus facile et aisé le contrôle du changement des valeurs.

En somme, nous avons à présent une compréhension plus poussée de l'essentiel à connaître sur les Signal Inputs. Nous aborderons dans de prochains articles, d'autres concepts liés à Angular Signal.

Pour plus d'informations 👉 Signal Inputs

Did you find this article valuable?

Support Ezéchiel Amen AGBLA by becoming a sponsor. Any amount is appreciated!