FrancescoDonzello
Angular Share on Twitter

Troubleshooting NG0950: Input is required but no value is available yet

4 minutes read
#articles#angular#troubleshooting

Introduction

When working with Angular components, you may encounter the NG0950: Input is required but no value is available yet error.

This error occurs when an @Input() or input() property is used before the framework has a value available for it.

The error

Let’s consider the following code:

client-autocomplete.component.ts
export class ClientAutocompleteComponent {
  private readonly _client = inject(ClientsService);
 
  readonly control = input.required<FormControl>();
 
  readonly clients = toSignal(
    this.control().valueChanges.pipe(
      takeUntilDestroyed(),
      debounceTime(300),
      distinctUntilChanged(),
      switchMap((query) => this._client.list(query)),
    ),
  );
}

At line 4, we’re using the input.required method to mark the control property as required. This means that the control input must be provided by the parent component.

At line 6, we’re using the control property to create an observable that fetches a list of clients based on the user’s input.

This code is concise and easy to understand, but if we run it, we’ll get the following error:

NG0950: Input 'control' is required but no value is available yet.

A possible solution

As stated in the official Angular documentation, the trick is to move the clients property initialization inside the ngOnInit lifecycle hook.

client-autocomplete.component.ts
export class ClientControlComponent implements OnInit {
  private readonly _client = inject(ClientsService);
  private readonly destroyRef = inject(DestroyRef);
 
  readonly control = input.required<FormControl>();
 
  clients: Signal<Client[] | undefined> | undefined;
 
  ngOnInit(): void {
    this.clients = toSignal(
      this.control().valueChanges.pipe(
        takeUntilDestroyed(this.destroyRef),
        debounceTime(300),
        distinctUntilChanged(),
        switchMap((query) => this._client.list(query)),
      ),
    );
  }
}

This change ensures that the control property is accessed after in the ngOnInit lifecycle hook, when the value is available.

However, this will raise another error:

NG0203: toSignal() can only be used within an injection context

The final solution

To fix every error, we need to modify a little bit the template.

client-autocomplete.component.html
<input
        #clientInput
        matInput
        type="text"
        [formControl]="control()"
        (input)="query.set(clientInput.value)"
        placeholder="Search..."
      />

At line 6, we’re using the input event to update the query signal when the user types something new.

client-autocomplete.component.ts
export class ClientControlComponent {
  private readonly _client = inject(ClientsService);
 
  readonly control = input.required<FormControl>();
  readonly query = signal<string>('');
 
  readonly clients = toSignal(
    toObservable(this.query).pipe(
      takeUntilDestroyed(),
      debounceTime(300),
      distinctUntilChanged(),
      tap((query) => console.log('query changed', query)),
      switchMap((query) => this._client.list(query)),
    ),
  );
}

At line 5, we introduce a new query signal that will be updated from the template.

At line 8, we convert the signal to an observable so that we can have a stream of values to work with.

With this implementation we get rid of:

Considerations

Altough the solution leads to a more verbose code, it’s possible that in the near future this behavior will be modified to work as expected.

← Back to Angular Articles

Was it helpful?

Tell your friends or co-workers.