Tim Deschryver

Required @Input() properties

This week I got asked how to make a component’s input property required. Without giving it much thought I started my answer ‘well, you can just …’, then I stopped asking myself the same question. So I opened a new StackBlitz project and started exploring the options before giving an answer.

Before we start let’s imagine we’re creating a component HelloComponent to greet a person. In order to greet the person properly, the person property is required.

The first thing that came to my mind was to throw an error when the person property would be null or undefined.

ngOnInit() {
  if (this.person === null || this.person === undefined) {
    throw new TypeError("The input ‘Person’ is required");
  }
}

This doesn’t change much except that it would throw a useful error message.
Before: ERROR TypeError: Cannot read property ‘name’ of null
After: ERROR TypeError: The input ‘Person’ is required

To make the requirement explicit we can use the selector in the @Component decorator to require that the attribute on our component has to exist.

@Component({
    selector: 'hello[person]'
})

Resulting in the following error when we start the application or at compile time when the application is build Ahead of Time (AoT), if the HelloComponent doesn’t have a person attribute.

Error: Template parse errors:
'hello' is not a known element:
1. If 'hello' is an Angular component, then verify that it is part of this module.
2. To allow any element add 'NO_ERRORS_SCHEMA' to the '@NgModule.schemas' of this component. ("[ERROR ->]<hello></hello>"): ng:///AppModule/AppComponent.html@0:0
Evaluating src/main.ts
Booting application

By putting the two together, I can say that I’m happy with the result.
If you got a better way or see a problem with this approach please feel free to let me know, feedback is as always welcome.
The question I’m asking myself right now, is if this is something that should be done in the first place… again let us know your opinion on this 😃.

Below you can find the two put together as well as the StackBlitz project ready for you to play with.

NOTE: I’m using _ngOnInit_ but like Isaac Mann mentioned you could also use _ngOnChanges_.

import { Component, Input, OnInit } from '@angular/core'
import { Person } from './person'

@Component({
  selector: 'hello[person]',
  template: `
    <h1>Hello {{ person.name }}!</h1>
  `,
})
export class HelloComponent implements OnInit {
  @Input() person: Person

  ngOnInit() {
    if (!this.person) {
      throw new TypeError("'Person' is required")
    }
  }
}