I’m encountering an interesting behavior in my Angular application, and I’m hoping someone can shed some light on it. Here’s the scenario:
I have a working code snippet where I define a property called isSelection
like this:
public isSelection = model.required<boolean>();
public getTypeof(value: any): string {
return typeof value;
}
The isSelection property is initialized with a model.required signal
<input type="checkbox" [(ngModel)]="isSelection" />
<p>{{ getTypeof(isSelection) }}</p>
I bind the isSelection property to a checkbox input using [(ngModel)]
The paragraph displays the type of isSelection
.
In this case the isSelection is displayed as a function when i press the checkbox the type of the isSelection never changed.
However, when I change the property declaration to:
public isSelection = input.required<boolean>();
The behavior changes, and the type of isSelection seems to switch from a function to a boolean
.
NB I'm using the last version of angular 17.3.1.
input.required<boolean>()
-> meant for one way binding, but you are using for two way binding, so the function gets replaced by a value that is boolean
To remedy this, we can use one way binding in HTML
<input type="checkbox" [ngModel]="isSelection2" />
When I use the code provided as a child and provide inputs from the parent, angular just throws an error when I try to use [(ngModel)]="isSelection2"
model.required<boolean>()
-> meant for two way binding, so your example works perfectly, since it does exactly what it's supposed to do!
See the below code/Stackblitz:
child
import { Component, input, model } from '@angular/core';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-child',
standalone: true,
imports: [FormsModule],
template: `
<input type="checkbox" [(ngModel)]="isSelection" />
<pre>{{ isSelection() }}</pre>
<p>{{ getTypeof(isSelection) }}</p>
<hr />
<input type="checkbox" [ngModel]="isSelection2" />
<pre>{{ isSelection2() }}</pre>
<p>{{ getTypeof(isSelection2) }}</p>
`,
})
export class ChildComponent {
public isSelection = model.required<boolean>();
public isSelection2 = input.required<boolean>();
public getTypeof(value: any): string {
return typeof value;
}
}
main.ts
import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { ChildComponent } from './app/child/child.component';
@Component({
selector: 'app-root',
standalone: true,
imports: [ChildComponent],
template: `<app-child [isSelection2]="true" [isSelection]="false"/>`,
})
export class App {}
bootstrapApplication(App);