#How to create a writable input signal with a possible provided default signal.

28 messages · Page 1 of 1 (latest)

quiet hearth
#

Can the following pattern be achieved in a simpler way?

Requirements:

  1. Writable signal input
  2. prioritize input values over the provided default signal

It feels weird calculating the first value since it should be the provided value when there is no input set. You kind of need to know if there was a input set.

const EXAMPLE_TOKEN = new InjectionToken<Signal<string>>('EXAMPLE_TOKEN');

  @Component({
    template: `{{ value() }}`,
  })
  class Example {
    readonly providedValue = inject(EXAMPLE_TOKEN, {
      optional: true,
    });

    readonly valueInput = input(
      this.providedValue?.() ?? 'initial input value',
      {
        alias: 'value',
      },
    );

    readonly value = linkedSignal({
      source: this.valueInput,
      computation: (higherPrioValue, previousValue) => {
        if (!isSignal(this.providedValue)) {
          return higherPrioValue;
        }

        const lowerPrioValue = this.providedValue();

        /**
         * The first value is always the higher priority value.
         *
         * If there is a new higher priority value, return it. If there is no
         * new higher priority value, we know there is a new lower priority
         * value.
         */

        if (!previousValue || higherPrioValue !== previousValue.source) {
          return higherPrioValue;
        }

        return lowerPrioValue;
      },
    });
  }
earnest otter
#
readonly providedValue = inject(EXAMPLE_TOKEN, { optional: true, });
  readonly valueInput = input<string>();
  readonly value = linkedSignal(() => {
    if (this.valueInput() !== undefined) return this.valueInput();
    return this.providedValue ? this.providedValue() : 'initial input value';
  });
quiet hearth
#

thank you, but providedValue() is never read when there is an input

earnest otter
#

Yea, you need the default value?

quiet hearth
#

Also when both signals changed in the same computation cycle, the input should take precedence

#

hm good question

earnest otter
#

i just follow your code and refactor, same output

quiet hearth
#

I think youre right, whenever there is an input the provided signal should be ignored

earnest otter
#

Btw:

this.providedValue?.() ?? 'initial input value'

?? is null coalesce?.() will returns undefined is there a ?: in typescript. || will block BlankString

#

hence i use this.providedValue ? this.providedValue() : 'initial input value'

quiet hearth
#

but the provided value could be the empty string, which is wanted in my case

earnest otter
#

Yes so this.providedValue ? this.providedValue() : 'initial input value' is correct.
this.providedValue is either a Signal or null

quiet hearth
#

true

earnest otter
#

if i do this.providedValue?.() || 'initial input value' then is incorrect. blank string blocked

quiet hearth
#

I kind of need meta information about the input signal, like .hasValue()

#

undefined could be a value aswell, no?

earnest otter
#

Once the caller <example [valueInput]="something">, he can't really change it to undefined anymore

#

undefined will be ignored

quiet hearth
#

oh really? Are there docs?

earnest otter
#

however it is not mandatory, initial <example [valueInput]="undefined"> is ok

quiet hearth
#

ye in that case undefined would be the value

earnest otter
#

but once you set it to something

#

you can't change to undefined. it is input<string> not input<string|undefined>

quiet hearth
#

maybe set the inital value to a Symbol and filter it out in the linked signal

earnest otter
#

Or just use '' to indicate you doesn't want it, or use null

quiet hearth
#

hmm i have to think about this, thank you for your thoughts

earnest otter
#

Yes, i did not change the behavior of your sample code, i only refactor it.
Except: this.providedValue?.() ?? 'initial input value' which i explained could have issue because ?? doesnt work ?.()

The nullish coalescing ( ?? ) operator is a logical operator that returns its right-hand side operand when its left-hand side operand is null or undefined. Javascript

#

Once the caller <example [valueInput]="something">, he can't really change it to undefined anymore

Will also apply to your code