Angular — Signal model
Well ! The new release of Angular V17 (version 17.2.1) is finally here, and with it, Angular’s team has brought the model signal based function.
What does it mean?!
Actually, this function is still in development, so the function may change in future releases.
This new function is very simple. According to the old way to transmit data and retrieve updates from the child to the parent, we had to write something like this:
@Component({
selector: 'app-root',
standalone: true,
template: `
<h1>My awesome app!<h1>
<p>The value of the variable : {{valueToSend}}</p>
<app-child [valueFromParent]="valueToSend"
(updateEvent)="updateValue($event)" />`})
export class AppComponent {
valueToSend : string = 'This is a value to send!';
updateEvent(newValue : string) : void {
this.valueToSend = newValue;
}
}
// the child component
@Component({
selector: 'app-child',
standalone: true,
template: `<h1>My child component!</h1>
<p>With the current value : {{valueFromParent}}</p>
<button type="button" (click)="updateValue()">Update value</button>`
})
export class ChildComponent {
@Input({required: true})
valueFromParent : string = '';
@Output()
updateEvent = new EventEmitter<string>();
updateValue() : void {
this.updateEvent.emit('Send updated value');
}
}
Another way exists to simplify a bit, and take advantage of the [()] syntax, mostly called the “banana in the box”:
@Component({
selector: 'app-root',
standalone: true,
template: `
<h1>My awesome app!<h1>
<p>The value of the variable : {{valueToSend}}</p>
<app-child [(valueFromParent)]="valueToSend" />`})
export class AppComponent {
valueToSend : string = 'This is a value to send!';
updateEvent(newValue : string) : void {
this.valueToSend = newValue;
}
}
// the child component
@Component({
selector: 'app-child',
standalone: true,
template: `<h1>My child component!</h1>
<p>With the current value : {{valueFromParent}}</p>
<button type="button" (click)="updateValue()">Update value</button>`
})
export class ChildComponent {
@Input({required: true})
valueFromParent : string = '';
@Output()
valueFormParentChange = new EventEmitter<string>();
updateValue() : void {
this.valueFormParentChange.emit('Send updated value');
}
}With this second possibility of writing the @Input/@Output we have to respect the expression imposed by the framework: somethingChange
Admit it… It’s not clear, there’s a lot of boilerplate that can be avoid.
Welcome to the new era of Angular !
With the last release of Angular, something magical comes with!
The Angular’s team, has brought with this release a new function called model().
Get Tahitoa Merlin’s stories in your inbox
Join Medium for free to get updates from this writer.
According to the official documentation of the function:
model declares a writeable signal that is exposed as an input/output pair on the containing directive. The input name is taken either from the class member or from the alias option. The output name is generated by taking the input name and appending Change.
Initializes a model with an initial value. If no explicit value is specified, Angular will use undefined.
Consider using model.required for models that don’t need an initial value.
Ok, well, and then what does it change?
Let’s take back the previous example, and change it to use the model function.
@Component({
selector: 'app-root',
standalone: true,
template: `
<h1>My awesome app!<h1>
<p>The value of the variable : {{valueToSend}}</p>
<app-child [(valueFromParent)]="valueToSend" />`})
export class AppComponent {
valueToSend : string = 'This is a value to send!';
}
// the child component
@Component({
selector: 'app-child',
standalone: true,
template: `<h1>My child component!</h1>
<p>With the current value : {{valueFromParent}}</p>
<button type="button" (click)="updateValue()">Update value</button>`
})
export class ChildComponent {
valueFromParent : ModelSignal<string> = model.require<string>();
updateValue() : void {
this.valueFromParent.update(() => 'Send updated value');
}
}It’s quite simple, isn’t it?
Should I always use the model to make two-way data binding?
The new model function, can be used as two-way data binding, but you can choose to make a one-way binding (from parent to child, or from child to parent).
Let’s check this!
@Component({
selector: 'app-root',
standalone: true,
template: `
<h1>My awesome app!<h1>
<p>The value of the variable : {{valueToSend}}</p>
<app-child [valueFromParent]="valueToSend" />`})
export class AppComponent {
valueToSend : string = 'This is a value to send!';
}
// the child component
@Component({
selector: 'app-child',
standalone: true,
template: `<h1>My child component!</h1>
<p>With the current value : {{valueFromParent()}}</p>
<button type="button" (click)="updateValue()">Update value</button>`
})
export class ChildComponent {
valueFromParent : ModelSignal<string> = model.require<string>();
updateValue() : void {
this.valueFromParent.update(() => 'Send updated value');
}
}By this way, only the child has an update on the value, which is bound to him. The parent is not impacted. This is the same if we use an event binding (from child to parent).
Remember that the input() function signal creates an input as a “read-only” signal, so the value can not be updated into the child.
What happens when using a signal variable?
And if we use a Signal input variable, what happens when we edit the input variable into the child?
Well, the principle of the data binding is the same, if we don’t transmit the new value with an event binding nothing happens to the parent value.
What is the next level?
The next level is the signal based component.
Actually, the Signal API works concurrently with the ZoneJS library. This is the library responsible for detect the changes made to the component.
According to the RFC — Signal-based component, the component will be able to be declared as signal-based component, meaning that all variables will be Signal. The signal-based Components, will be more concise in terms of life-cycle hook, only the following from known life-cycle will remain : ngOnInit/ngOnDestroy. To complete these two hooks, three functions will be available : afterNextRender/afterRender/afterRenderEffect
That’s all for today! Enjoy this new way to declare two-way data binding.








