I think I'm missing something very basic here, but I've been staring at this for too long. According the docs and everything else I've seen, an Angular directive's @Input()
will be accessible on a component as long as it's explicitly declared on the hostDirectives.inputs
of that component. That's not the behavior I'm seeing. Instead, I get the dreaded Property [propertyName] does not exist on type [componentName]
error.
Comment out line #26 on my Stackblitz to see it.
@Directive({
standalone: true,
})
export class CompositionTestDirective {
@Input() dataProperty?: string;
}
@Component({
selector: 'app-composition-test',
standalone: true,
template: `<h1> {{dataProperty}} </h1>`,
hostDirectives: [
{
directive: CompositionTestDirective,
inputs: ['dataProperty'],
},
],
})
export class CompositionTestComponent {
/* This shouldn't be necessary right? Comment this out and...KABOOM! */
@Input() dataProperty: string = '';
}
@Component({
selector: 'app-root',
standalone: true,
imports: [CompositionTestComponent],
template: `
<app-composition-test [dataProperty]="property"/>
`,
})
export class App {
property = 'It works!';
}
You can se that the error reference to the missing property in the HTML template of CompositionTestComponent
, so it's not a matter of Input
exposed.
In fact, when you omitted dataProperty
you were trying to reference the component's dataProperty
in the template, but it that didn't exist (causing the error). On the other hand, while you declared the Input
dataProperty
in the component, you weren't using the Directive
because from the parent component you were assigning dataProperty
.
I'm afraid that in order to access dataProperty
you have to access CompositionTestDirective
via dependency injection.
Note that in the constructor you can't be sure it's valued, if you want to reassign its value to a CompositionTestComponent
property you have to use the OnInit
hook.
It's not very elegant, but I'm afraid it's the best result achievable.
Here's your StackBlitz modified:
export class CompositionTestComponent {
testDirective = inject(CompositionTestDirective);
dataProperty?: string;
ngOnInit() {
this.dataProperty = this.testDirective.dataProperty;
}
}
<h1> from component: {{dataProperty}} </h1>
<h1> from directive: {{testDirective.dataProperty}} </h1>