Paweł Chabros
Paweł Chabros

Reputation: 2399

Default value for signal input based on other signal input

I would like to specify default value for signal input that is based on other signal input. This is what I tried:

import { Component, input } from '@angular/core';

@Component({
  selector: 'my-input',
  standalone: true,
  template: `
    <input
      type="number"
      [min]="min()"
      [max]="max()"
      [value]="value()"
    >
  `,
})
export class MyInput {
  min = input(0);
  max = input(100);
  value = input<number | undefined, number>(undefined, {
    transform: (value) => value || this.min(),
  });
}

But transform function is not even triggered. To force transform function trigger i have to pass some value to the component:

<my-input [value]="undefined" />

Is it possible to make it work without passing undefined?

Upvotes: 1

Views: 3287

Answers (1)

Naren Murali
Naren Murali

Reputation: 57721

We can also use a computed signal to limit the range or perform any transformations like how we do with transform!

child

import { Component, computed, input } from '@angular/core';

@Component({
  selector: 'my-input',
  standalone: true,
  imports: [],
  template: `
    <input
      type="number"
      [min]="min()"
      [max]="max()"
      [value]="limitedValue()"
    >
    {{min()}}
  `,
  styleUrl: './test.component.css',
})
export class TestComponent {
  min = input<number>(0);
  max = input<number>(100);
  value = input<number>();
  limitedValue = computed(() => {
    const max = this.max(),
      min = this.min(),
      value = this.value() || min;
    return value > max ? max : value < min ? min : value;
  });
}

parent

import { Component } from '@angular/core';
import { FormsModule } from '@angular/forms';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { TestComponent } from './app/test/test.component';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [TestComponent, FormsModule],
  template: `
    <my-input />
    <my-input [value]="value" [min]="5"/>
    <my-input [value]="5" [min]="5"/>
    <br/> changing input <input [(ngModel)]="value"/>
  `,
})
export class App {
  value = 0;
  name = 'Angular';
}

bootstrapApplication(App);

Stackblitz Demo


this below code does not work when min gets set, go for first one!

I would just set min as the default value of the signal, then I am guessing you want to limit the input value within a range, so we can apply that logic on the transform using comparison operators!

Child:

import { Component, input } from '@angular/core';

@Component({
  selector: 'my-input',
  standalone: true,
  imports: [],
  template: `
    <input
      type="number"
      [min]="min()"
      [max]="max()"
      [value]="value()"
    >
  `,
  styleUrl: './test.component.css',
})
export class TestComponent {
  min = input(0);
  max = input(100);
  value = input<number | undefined, number>(this.min(), {
    transform: (value) => {
      const max = this.max(),
        min = this.min();
      return value > max ? max : value < min ? min : value;
    },
  });
}

Parent:

import { Component } from '@angular/core';
import { bootstrapApplication } from '@angular/platform-browser';
import 'zone.js';
import { TestComponent } from './app/test/test.component';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [TestComponent],
  template: `
    <my-input />
    <my-input [value]="1000"/>
    <my-input [value]="1000"/>
  `,
})
export class App {
  name = 'Angular';
}

bootstrapApplication(App);

Stackblitz Demo

Upvotes: 1

Related Questions