Dans notre précédent article, nous avons vu ensemble ce qu'est un Signal Input
et comment l'utiliser. Nous avons particulièrement remarqué sa similarité avec le décorateur @Input()
.
Dans ce nouvel article, nous verrons ensemble un nouveau type de input qui est toujours basé sur Angular Signal
. Ce nouveau type de input a été conçu de façon très ingénieuse et est aussi très similaire à une fonctionnalité existante de Angular qui est très utilisée. Découvrons-le ensemble sans plus attendre !
Qu'est-ce qu'un Model Input
en Angular ?
En nous basant sur la documentation de Angular, un Model Input
est un type spécial d'input qui permet à un composant A de propager de nouvelles valeurs vers un composant B. En effet, lorsqu'on analyse cette définition, ce qui nous vient à l'esprit c'est qu'un Model Input
fait la même chose qu'un Signal Input
dans le fonctionnement comme l'indique cet exemple :
import {Component, model, input} from '@angular/core';
@Component({...})
export class CustomCheckbox {
// This is a model input.
checked = model(false);
// This is a standard input.
disabled = input(false);
}
<!--- Parent component side --->
<custom-checkbox [checked]="true" [disabled]="false" />
Le code ci-dessus nous démontre que les deux types d'input à savoir Signal Input
et Model Input
permettent de faire le one-way binding
c'est-à-dire dans notre cas ici la communication unidirectionnelle d'un composant parent vers un composant enfant et non l'inverse.
Cependant, le Model Input
ne se limite pas à cela. Dans sa philosophie de propager de nouvelles valeurs, le Model Input
est également accessible en écriture contrairement à un Signal Input
. Nous pouvons donc modifier la valeur d'un Model Input
depuis le composant enfant où il a été instancié ce qui n'est pas le cas du Signal Input
qui est read-only
. Voici une illustration :
import {Component, model, input} from '@angular/core';
@Component({
selector: 'custom-checkbox',
template: '<div (click)="toggle()"> ... </div>',
})
export class CustomCheckbox {
checked = model(false);
disabled = input(false);
toggle() {
// While standard inputs are read-only, you can write directly to model inputs.
this.checked.set(!this.checked());
}
}
Dans l'illustration de code ci-dessus, nous remarquons l'utilisation de la méthode set()
sur notre Model Input
. Nous pouvons en déduire que la méthode update()
aussi peut être utilisée et pour conclure que notre Model Input
est un WritableSignal
.
Pour finir, en nous basant sur les deux extraits de code précédent, on peut facilement émettre l'hypothèse suivante :
Lorsque le composant parent ou enfant (peu importe l'un des deux) écrit une nouvelle valeur dans le Model Input, Angular peut propager cette nouvelle valeur vers le composant qui lie cette valeur.
En effet, c'est typiquement le fonctionnement du Model Input
. Il ne permet pas que la liaison unidirectionnelle (one-way binding
) mais également la liaison bidirectionnelle (two-way binding
). Tout ceci nous fait penser à ngModel
que nous utilisons déjà énormément dans Angular.
Two-way binding
avec Model Input
La documentation de Angular nous présente deux situations différentes pour l'utilisation du two-way binding
en se basant sur Angular Signal
ou sur du JS/TS
classique.
Two-way binding
avec duJS/TS
classique :
@Component({
...,
// `checked` is a model input.
// The parenthesis-inside-square-brackets syntax (aka "banana-in-a-box") creates a two-way binding
template: '<custom-checkbox [(checked)]="isAdmin" />',
})
export class UserProfile {
protected isAdmin = false;
}
Dans l'exemple ci-dessus, le composant CustomCheckbox
peut écrire des valeurs dans checked
, qui propage ensuite ces valeurs vers la propriété isAdmin
dans UserProfile
. Cette liaison permet de synchroniser les valeurs de checked
et de isAdmin
.
Two-way binding
avecAngular Signal
:
@Component({
...,
// `checked` is a model input.
// The parenthesis-inside-square-brackets syntax (aka "banana-in-a-box") creates a two-way binding
template: '<custom-checkbox [(checked)]="isAdmin" />',
})
export class UserProfile {
protected isAdmin = signal(false);
}
Dans cet exemple ci-dessus, le CustomCheckbox
peut écrire des valeurs dans checked
, qui propage ensuite ces valeurs vers isAdmin
dans UserProfile
. Cette liaison permet de synchroniser les valeurs de checked
et de isAdmin
. Cependant, il est très important de noter qu'ici, la liaison transmet le signal isAdmin
lui-même, et non la valeur du signal.
Pour finir, en nous basant sur le principe du two-way binding
, lorsque nous déclarons un Model Input
dans un composant ou une directive, Angular crée automatiquement un event
correspondant. Voici un exemple :
@Directive({...})
export class CustomCheckbox {
// This automatically creates an output named "checkedChange".
// Can be subscribed to using `(checkedChange)="handler()"` in the template.
checked = model(false);
}
Angular émet cet event
de changement chaque fois que nous écrivons une nouvelle valeur dans le Model Input
en appelant les méthodes set()
ou update()
.
Différences entre model()
et input()
Nous avons commencé cet article en essayant de voir la similarité entre un Signal Input
et un Model Input
. A présent, nous verrons les éléments qui les différencient :
model()
définit à la fois uninput
et unoutput
. Le nom de l'output
est toujours le nom de l'input
suffixé parChange
pour prendre en charge les liaisons bidirectionnelles. C'est au composant qui l'implémente de décider s'il veut utiliser seulement l'input
, seulement l'output
, ou les deux.ModelSignal
est unWritableSignal
, ce qui signifie que sa valeur peut être modifiée de n'importe où à l'aide des méthodesset()
etupdate()
. Lorsqu'une nouvelle valeur est attribuée, leModelSignal
émet unoutput
. Il en va différemment de l'InputSignal
, qui est enread-only
.Les
Model Inputs
ne prennent pas en chargetransform
, contrairement auxSignal Inputs
.
En somme, dans cet article, l'objectif a été de vulgariser le concept de Model Input
. Bien qu'ayant une similarité avec le Signal Input
, nous avons remarqué qu'il est beaucoup plus proche de la philosophie autour du ngModel
à travers le two-way binding
mais basé sur Angular Signal
. Toutefois, il faut noter que Model Input
est toujours Developer Preview.
Pour plus d'informations 👉 Model Inputs