Angular Behavior: Property Type Changes from SignalFunction to Boolean

33 views Asked by At

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.

1

There are 1 answers

5
Naren Murali On BEST ANSWER

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);

Working Stackblitz