In AngularJs we could make a directive attribute required. How do we do that in Angular with @Input? The docs don't mention it.
Eg.
@Component({
selector: 'my-dir',
template: '<div></div>'
})
export class MyComponent {
@Input() a: number; // Make this a required attribute. Throw an exception if it doesn't exist.
@Input() b: number;
}
Here is another TypeScript decorator based approach that is less complicated and easier to understand. It also supports Component inheritance.
Why not use the
@angular/forms
library to validate your@Input
s? The following solution:@input
value is accessed by the component for the first time)Usage:
Utility function:
Stackblitz
For me, I had to do it this way:
FYI, If you want to require @Output directives, then try this:
Official solution
As answered by Ryan Miglavs – smart usage of Angular's selectors solves the issue. Personally I prefer this way in most cases, as it doesn't require any additional effort during the codding time. However, it has some disadvantages:
For alternative solutions – look below, they require some additional codding, but doesn't have disadvantages described above.
So, here is my solution with getters/setters. IMHO, this is quite elegant solution as everything is done in one place and this solution doesn't require
OnInit
dependency.Solution #1
Solution #2:
It could be done even easier with decorators. So, you define in your app once decorator like this one:
And later in your class you just need to mark your property as required like this:
Explanation:
If attribute
a
is defined - setter of propertya
will override itself and value passed to attribute will be used. Otherwise - after component init - first time you want to use propertya
in your class or template - error will be thrown.Note: getters/setters works well within Angular's components/services, etc and it's safe to use them like this. But be careful while using this approach with pure classes outside Angular. The problem is how typescript converts getters/setters - they are assigned to
prototype
property of the class. In this case we do mutate prototype property which will be the same for all instances of class. Means we can get something like this:You can do it like this:
The official Angular way to do this is to include the required properties in the selector for your component. So, something like:
The advantage to this is that if a developer does not include the property (
a
) when referencing the component in their template, the code won't compile. This means compile-time safety instead of run-time safety, which is nice.The bummer is that the error message the developer will receive is "
my-dir
is not a known element", which isn't super clear.I tried the decorator approach mentioned by ihor, and I ran into issues since it applies to the Class (and therefore after TS compilation to the prototype), not to the instance; this meant that the decorator only runs once for all copies of a component, or at least I couldn't find a way to make it work for multiple instances.
Here are the docs for the selector option. Note that it actually allows very flexible CSS-style selector-ing (sweet word).
I found this recommendation on a Github feature request thread.